【洛谷P4735】最大异或和
题目大意:给定一个长度为 N 的序列,支持两个操作:在序列末尾添加一个新的数字,查询序列区间 \([l,r]\) 内使得 \(a_p\oplus a_{q+1}\oplus ... a_N\oplus x\) 值最大。
题解:由于是查询区间的最大异或值,可知应该使用可持久化数据结构,再由于是最大异或和,可知采用可持久化 Trie + 前缀和处理。在 Trie 的每个节点上维护一个 size,表示该节点是多少个数字的二进制前缀,查询过程类似于主席树。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn = 6e5 + 10;
struct node {
node *l, *r;
int sz;
void pull() {
this->sz = 0;
if (l != NULL) {
this->sz += l->sz;
}
if (r != NULL) {
this->sz += r->sz;
}
}
} pool[maxn * 24];
node *newnode() {
static int cnt = 0;
return &pool[cnt++];
}
node *insert(node *pre, int bit, int val) {
node *cur = newnode();
if (pre) {
*cur = *pre;
}
if (bit < 0) {
cur->sz++;
return cur;
}
if (val >> bit & 1) {
cur->r = insert(pre ? pre->r : NULL, bit - 1, val);
} else {
cur->l = insert(pre ? pre->l : NULL, bit - 1, val);
}
cur->pull();
return cur;
}
int query(node *cur, node *pre, int bit, int val) {
if (bit < 0) {
return 0;
}
int now = val >> bit & 1;
if (now == 0) {
int rsz = 0;
if (cur && cur->r) rsz += cur->r->sz;
if (pre && pre->r) rsz -= pre->r->sz;
if (rsz > 0) {
return (1 << bit) + query(cur ? cur->r : NULL, pre ? pre->r : NULL, bit - 1, val);
} else {
return query(cur ? cur->l : NULL, pre ? pre->l : NULL, bit - 1, val);
}
} else {
int lsz = 0;
if (cur && cur->l) lsz += cur->l->sz;
if (pre && pre->l) lsz -= pre->l->sz;
if (lsz > 0) {
return (1 << bit) + query(cur ? cur->l : NULL, pre ? pre->l : NULL, bit - 1, val);
} else {
return query(cur ? cur->r : NULL, pre ? pre->r : NULL, bit - 1, val);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector<int> sum(n + 1);
vector<node*> rt(n + 1);
rt[0] = insert(NULL, 25, 0);
for (int i = 1, x; i <= n; i++) {
cin >> x;
sum[i] = sum[i - 1] ^ x;
rt[i] = insert(rt[i - 1], 25, sum[i]);
}
while (m--) {
string opt;
cin >> opt;
if (opt[0] == 'A') {
int x;
cin >> x;
int val = sum.back() ^ x;
sum.push_back(val);
node *cur = insert(rt.back(), 25, val);
rt.push_back(cur);
} else {
int l, r, x;
cin >> l >> r >> x;
l--, r--;
if (l == 0) {
cout << query(rt[r], NULL, 25, x ^ sum.back()) << endl;
} else {
cout << query(rt[r], rt[l - 1], 25, x ^ sum.back()) << endl;
}
}
}
return 0;
}