题目大意:
给定一个非负整数序列{a},初始长度为N。
有M个操作,有以下两种操作类型:
1. A x:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。
2. Q l r x:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:
a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少。
解题思路:
首先,a[1] xor a[2] xor ... xor a[N] xor x很容易求出。
然后,异或满足交换律和结合律。
此处询问的是后缀,我们考虑转化成前缀异或。
设s[i]表示a[1] xor a[2] xor ... xor a[i]
即在\([l-1,r-1]\)中找一个数p,使s[N] xor x xor s[p]最大。
用可持久化Trie维护前缀异或信息,和节点个数,然后在区间内进行前缀差查询(可持久化Trie满足可加性),每次贪心地使高位尽可能大即可。
于是长得和主席树差不多。
毒瘤数据结构大法好o((⊙﹏⊙))o
C++ Code:
#include<bits/stdc++.h>
int n,m,s[600006],b[25],cnt=0,ans,rt[600006];
struct node{
int ch[2],c;
}d[22000006];
void add(int&o,int&pr,int nw){
o=++cnt;
if(!~nw){d[o].c=d[pr].c+1;return;}
d[o].ch[0]=d[pr].ch[0];
d[o].ch[1]=d[pr].ch[1];
add(d[o].ch[b[nw]],d[pr].ch[b[nw]],nw-1);
d[o].c=d[d[o].ch[0]].c+d[d[o].ch[1]].c;
}
void ask(int&R,int&L,int nw){
if(!~nw)return;
int _1=b[nw]^1;
if(d[d[R].ch[_1]].c>d[d[L].ch[_1]].c){
ans|=1<<nw;
ask(d[R].ch[_1],d[L].ch[_1],nw-1);
}else
ask(d[R].ch[b[nw]],d[L].ch[b[nw]],nw-1);
}
inline int readint(){
int c=getchar(),d=0;
for(;!isdigit(c);c=getchar());
for(;isdigit(c);c=getchar())
d=(d<<3)+(d<<1)+(c^'0');
return d;
}
int main(){
n=readint(),m=readint();
s[0]=0;
for(int i=1;i<=n;++i){
int q=readint();
s[i]=s[i-1]^q;
for(int j=24;~j;--j)
b[j]=(s[i]>>j)&1;
add(rt[i],rt[i-1],24);
}
while(m--){
char c[2];
scanf("%s",c);
if(c[0]=='A'){
int q=readint();
++n;
s[n]=s[n-1]^q;
for(int j=24;~j;--j)
b[j]=(s[n]>>j)&1;
add(rt[n],rt[n-1],24);
}else{
ans=0;
int l=readint(),r=readint(),x=readint(),p;
p=s[n]^x;
if(r==1){
printf("%d\n",p);
continue;
}
for(int j=24;~j;--j)
b[j]=(p>>j)&1;
ask(rt[r-1],l-2>0?rt[l-2]:rt[0],24);
printf("%d\n",ans);
}
}
return 0;
}