题目链接
题解
终于学会了可持久化trie
树了。感觉并不是特别的难。
因为可持久化,那么我们就考虑动态开点的trie
树。
都知道异或操作是有传递性的,那么我们就维护一个前缀异或和。
【最长异或距离】
可以参考以上这一道题目的贪心策略。
每次找到另外一边的(说的清楚一点就是每一次找字典树的儿子都找异或的数当前这一位的异或1
的值),这样可以保证疑惑后答案最大。
参照主席树的区间最小的求法:【洛谷的模板】
每一次我们就查找root[l - 1] ~ root[r]
区间内的答案就可以了。
一开始不理解可持久化01字典树的原因是因为我不知道为什么字典树里面需要有31
这个东西
然后我就发现了这个31
其实就是普通字典树里面的字符串的长度的意思。
真的是石乐志了。qwq
那么可持久化01trie
的模板如下
插入操作
void ins(int &rt, int pre, int val, int len) {
rt = ++ tot; int k = rt;
for (int i = len; ~i; i --) {
ch[k][0] = ch[pre][0]; ch[k][1] = ch[pre][1]; cnt[k] = cnt[pre] + 1;
int p = (val >> i) & 1;
ch[k][p] = ++ tot;
k = ch[k][p]; pre = ch[pre][p];
}
cnt[k] = cnt[pre] + 1;
}
其他的操作和普通的字典树是一样的。
代码
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define ms(a, b) memset(a, b, sizeof(a))
#define ll long long
#define ull unsigned long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define db double
#define Pi acos(-1)
#define eps 1e-8
#define N 600005
using namespace std;
template <typename T> T power(T x, T y, T mod) { x %= mod; T res = 1; for (; y; y >>= 1) { if (y & 1) res = (res * x) % mod; x = (x * x) % mod; } return res; }
template <typename T> void read(T &x) {
x = 0; T fl = 1; char ch = 0;
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') fl = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
x *= fl;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10); putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) { write(x); puts(""); }
struct L_Trie {
int ch[N * 40][2], cnt[N * 40], tot;
void ins(int &rt, int pre, int val, int len) {
rt = ++ tot; int k = rt;
for (int i = len; ~i; i --) {
ch[k][0] = ch[pre][0]; ch[k][1] = ch[pre][1]; cnt[k] = cnt[pre] + 1;
int p = (val >> i) & 1;
ch[k][p] = ++ tot;
k = ch[k][p]; pre = ch[pre][p];
}
cnt[k] = cnt[pre] + 1;
}
int query(int x, int y, int val, int len) {
int res = 0;
for (int i = len; ~i; i --) {
int p = (val >> i) & 1;
if (cnt[ch[y][p ^ 1]] - cnt[ch[x][p ^ 1]] > 0) { res += (1 << i); x = ch[x][p ^ 1]; y = ch[y][p ^ 1]; }
else x = ch[x][p], y = ch[y][p];
}
return res;
}
} trie;
int root[N], sumxor[N];
char opt[5];
int n, m;
int main() {
read(n); read(m);
trie.ins(root[0], root[0], 0, 31);
for (int i = 1; i <= n; i ++) {
int x; read(x);
sumxor[i] = sumxor[i - 1] ^ x;
trie.ins(root[i], root[i - 1], sumxor[i], 31);
}
for (int i = 1; i <= m; i ++) {
scanf("%s", opt); int x, l, r;
if (opt[0] == 'A') {
read(x); ++ n; sumxor[n] = sumxor[n - 1] ^ x;
trie.ins(root[n], root[n - 1], sumxor[n], 31);
}
else {
read(l); read(r); read(x); l --; r --;
printf("%d\n", trie.query(root[l - 1], root[r], x ^ sumxor[n], 31));
}
}
return 0;
}