您的位置:首页 > 其它

【BZOJ 4571】【SCOI 2016】美味

2017-03-20 18:25 357 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=4571

这道题因为有加法,不能像可持久化trie那样每次判断只判断一个子树,而是在主席树上查询\(\log n\)个子树。

从高位到低位依次确定\(a_j+x_i\)的二进制位。

注意\(a_j+x_i\)不是\(10^5\)级别的,是两倍大小。

时间复杂度\(O(n\log n+m\log^2n)\)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 200003;

struct node {
int s, l, r;
} T[N * 20];

int cnt = 0, root
, n, m;

void update(int &pos, int l, int r, int key) {
T[++cnt] = T[pos]; pos = cnt; ++T[pos].s;
if (l == r) return;
int mid = (l + r) >> 1;
if (key <= mid) update(T[pos].l, l, mid, key);
else update(T[pos].r, mid + 1, r, key);
}

int Q(int TL, int TR, int l, int r, int L, int R) {
if (L <= l && r <= R) return T.s - T[TL].s;
if (T.s - T[TL].s == 0) return 0;
int mid = (l + r) >> 1, s = 0;
if (L <= mid) s += Q(T[TL].l, T.l, l, mid, L, R);
if (R > mid) s += Q(T[TL].r, T.r, mid + 1, r, L, R);
return s;
}

void solve(int b, int x, int TL, int TR) {
int v, num = 0, numl, numr;
for (int i = 17; i >= 0; --i) {
v = (b >> i) & 1 ^ 1;
numl = num | (v << i); numr = numl | (1 << i) - 1;
if (Q(TL, TR, 0, 99999, numl - x, numr - x))
num |= (v << i);
else
num |= ((v ^ 1) << i);
}
printf("%d\n", num ^ b);
}

int main() {
scanf("%d%d", &n, &m);
int ai;
for (int i = 1; i <= n; ++i) {
scanf("%d", &ai);
root[i] = root[i - 1];
update(root[i], 0, 99999, ai);
}

int bi, xi, l, r;
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d%d", &bi, &xi, &l, &r);
solve(bi, xi, root[l - 1], root[r]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: