分析
添加操作很好办,我们先放一放
来看询问操作
求最大
我们知道xor有自反性
所以上面那个式子就等价于 (令S[i]=a[1] xor a[2] xor .... xor a[i])
又因为后面两个是可以看做定值,我们令Val=S[n] xor X
现在问题就转化为当p>=l&&p<=r时,找到一个S使得S xor Val的值最大
这就是一个很经典的区间异或最大值了,我们用可持久化trie树来实现
需要注意几点:
- 由于我们找的是S[p-1] 所以为了避免查询的时候访问到了负数,我们在S[]数组中多放一个0,也就是说S[1] = 0
- (x>>i )&1和(1<<i)&x,这两个是不一样的,前者只会出现0或1,后者只有当 x 对应的那一位为0时,才是0
- cin慢到飞起……用cin 3000多ms,改成scanf后直接A了
代码
空间随便开的……不具备参考性
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 300009
#define in read()
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
int n,m,a,rt[300005*100],tot=0;
struct node{
int cnt,l,r;
}tr[300005*100];
inline void insert(int pre,int &now,int x,int dep){
tr[now=++tot]=tr[pre];
tr[now].cnt++;
if(dep==-1) return;
//int c=x&(1<<dep);
int c=(x>>dep)&1;
if(!c) insert(tr[pre].l,tr[now].l,x,dep-1);
else insert(tr[pre].r,tr[now].r,x,dep-1);
}
int ans=0;
inline void query(int R,int L,int x,int dep){
if(dep==-1) return ;
// int c=x&(1<<dep);
int c=(x>>dep)&1;
c^=1;
if(!c) {
if(tr[tr[R].l].cnt-tr[tr[L].l].cnt) ans=ans|(1<<dep),query(tr[R].l,tr[L].l,x,dep-1);
else query(tr[R].r,tr[L].r,x,dep-1);
}
else{
if(tr[tr[R].r].cnt-tr[tr[L].r].cnt) ans=ans|(1<<dep),query(tr[R].r,tr[L].r,x,dep-1);
else query(tr[R].l,tr[L].l,x,dep-1);
}
}
int sum[600005];
int main(){
n=in;m=in;n++;
int i,j,k;
rt[0]=0;
for(i=2;i<=n;++i){//从2开始
sum[i]=sum[i-1]^in;
}
for(i=1;i<=n;++i)
insert(rt[i-1],rt[i],sum[i],25);
char ch[5];
int x,l,r;
for(i=1;i<=m;++i){
scanf("%s",ch);
if(ch[0]=='A'){
x=in;
++n;sum[n]=sum[n-1]^x;
insert(rt[n-1],rt[n],sum[n],25);
}
else{
l=in;r=in;x=in^sum[n];
ans=0;
query(rt[r],rt[l-1],x,25);
cout<<ans<<'\n';
}
}
return 0;
}