基本思想:
- 对于每个询问,要求x^(ap^ap+1^...^an),首先关注后半部分.
- 对于(ap^ap+1^...^an),可以联想到树状数组中的前缀和相减,于是思考前缀异或和是否也能转换成这种形式.
- 设bi=a1^a2^...^ai,1<j<i,显然bj=a1^a2^...^aj.
- 则bi可转化为bj^...^ai的形式.
- 由于异或操作"自消"的性质,可以发现bj^bj=0,因此bi^bj=0^aj+1^aj+2^...^ai=aj+1^aj+2^...^ai,即aj+1至ai的区间异或和.
易错点:
- MAXINDEX比MAXN大很多.
#include<cstdio> #include<iostream> using namespace std; const int MAXN=6e5,MAXM=6e5; struct Node{ int son[2]; int latest; }tr[MAXN*24]; int nodeCnt=0; void insert(int p,int &q,int nowRoot,int val,int k){ if(!q)q=++nodeCnt; tr[q].latest=nowRoot; if(k<0)return; bool c=(val>>k)&1; tr[q].son[c^1]=tr[p].son[c^1]; insert(tr[p].son[c],tr[q].son[c],nowRoot,val,k-1); } int query(int now,int latest,int val,int k){ if(k<0)return tr[now].latest; bool c=(val>>k)&1; if(tr[tr[now].son[c^1]].latest>=latest)return query(tr[now].son[c^1],latest,val,k-1); else return query(tr[now].son[c],latest,val,k-1); } int root[MAXN],b[MAXN],rootCnt=0; int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int tmp; scanf("%d",&tmp); rootCnt++; b[rootCnt]=b[rootCnt-1]^tmp; insert(root[rootCnt-1],root[rootCnt],rootCnt,b[rootCnt],25); } tr[0].latest=-1; for(int i=1;i<=m;i++){ char opt[10]; scanf("%s",opt); if(opt[0]=='A'){ int x; scanf("%d",&x); rootCnt++; b[rootCnt]=b[rootCnt-1]^x; insert(root[rootCnt-1],root[rootCnt],rootCnt,b[rootCnt],25); }else if(opt[0]=='Q'){ int l,r,x; scanf("%d%d%d",&l,&r,&x); int nowVal=b[rootCnt]^x; int p=query(root[r-1],l-1,nowVal,25); int ans=b[p]^nowVal; printf("%d ",ans); } } return 0; }