Description
给定一个非负整数序列{a},初始长度为N。
有M个操作,有以下两种操作类型:
1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。
2、Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:
a[p] xor a[p+1] xor … xor a[N] xor x 最大,输出最大是多少。
Sample Input
5 5
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6
Sample Output
4
5
6
这道题首先可以想到01字典树吗,它又询问区间,又带插入,那就很容易想到可持久化,那不就成了道版题吗。。。
#include <cstdio>
#include <cstring>
using namespace std;
struct trnode {
int c[2], s;
} t[26 * 610000]; int cnt, rt[610000];
char ss[10];
void Link(int u, int d) {
for(int i = 25; i >= 0; i--) {
int hh = 0; t[u].s++;
if(d >= (1 << i)) hh = 1, d -= (1 << i);
if(!t[u].c[hh]) t[u].c[hh] = ++cnt;
u = t[u].c[hh];
} t[u].s++;
}
void Merge(int &u1, int u2) {
if(!u1 || !u2) {u1 = u1 + u2; return ;}
t[u1].s += t[u2].s;
Merge(t[u1].c[0], t[u2].c[0]);
Merge(t[u1].c[1], t[u2].c[1]);
}
int query(int u1, int u2, int d) {
int ans = 0;
for(int i = 25; i >= 0; i--) {
int hh = 0;
if(d >= (1 << i)) hh = 1, d -= (1 << i);
if(t[t[u2].c[hh ^ 1]].s - t[t[u1].c[hh ^ 1]].s) ans += (1 << i), u1 = t[u1].c[hh ^ 1], u2 = t[u2].c[hh ^ 1];
else u1 = t[u1].c[hh], u2 = t[u2].c[hh];
}
return ans;
}
int main() {
int n, m; scanf("%d%d", &n, &m);
rt[0] = ++cnt; Link(rt[0], 0);
int now = 0, len = n;
for(int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
now ^= x; rt[i] = ++cnt;
Link(rt[i], now); Merge(rt[i], rt[i - 1]);
}
for(int i = 1; i <= m; i++) {
scanf("%s", ss + 1);
if(ss[1] == 'A') {
int x; scanf("%d", &x);
now ^= x; rt[++len] = ++cnt;
Link(rt[len], now); Merge(rt[len], rt[len - 1]);
}
else {
int l, r, x; scanf("%d%d%d", &l, &r, &x);
int ll, rr = rt[r - 1];
if(l != 1) ll = rt[l - 2];
else ll = 0;
printf("%d\n", query(ll, rr, now ^ x));
}
}
return 0;
}