【BZOJ 4571】【SCOI 2016】美味
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], 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[TR].s - T[TL].s;
if (T[TR].s - T[TL].s == 0) return 0;
int mid = (l + r) >> 1, s = 0;
if (L <= mid) s += Q(T[TL].l, T[TR].l, l, mid, L, R);
if (R > mid) s += Q(T[TL].r, T[TR].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;
}
NOI 2017 Bless All