显然,第一二种询问是等价的,可以用前缀异或和解决。
对于第三种询问,可以维护一个链表,一个数指向下一个与它相等的数的位置,并记下上一个与它相等的数的位置。
询问排序后(左端点为第一关键字,右端点为第二关键字),使用树状数组处理询问,树状数组的下标是同学的编号。当删除一个数的时候,只需要把这个数指向的下一个位置加入树状数组。
#include
#include
#include
#define N 500100
using namespace std;
struct node{int Type,l,r,id;}que[N];
bool cmp(node a,node b){
if(a.l==b.l)return a.rreturn a.lint Next[N],First[N],cnt,n;
int Lowbit(int x){return x&-x;}
int Tree[N];
void Add(int x,int w){
if(!x)return;
for(int i=x;i<=n;i+=Lowbit(i))Tree[i]^=w;
}
int Get(int x){
if(!x)return 0;
int Ans=0;
for(int i=x;i;i-=Lowbit(i))Ans^=Tree[i];
return Ans;
}
int A[N],Mat[N],B[N],D[N],Ans[N];
int main(){
int m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&A[i]),Mat[i]=A[i],B[i]=B[i-1]^A[i];
sort(Mat+1,Mat+n+1);
int k=unique(Mat+1,Mat+n+1)-Mat-1;
for(int i=n;i;i--){
D[i]=lower_bound(Mat+1,Mat+k+1,A[i])-Mat;
Next[i]=First[D[i]],First[D[i]]=i;
}
for(int i=1;i<=n;i++)if(First[D[i]]==i)Add(i,A[i]);
for(int i=1;i<=m;i++)
scanf("%d",&que[i].Type),que[i].id=i,
scanf("%d%d",&que[i].l,&que[i].r);
sort(que+1,que+m+1,cmp);
for(int i=1,k=1;i<=m;i++){
if(que[i].Type!=3){
Ans[que[i].id]=B[que[i].r]^B[que[i].l-1];
continue;
}
while(kif(Next[k])Add(Next[k],A[Next[k]]);k++;}
Ans[que[i].id]=B[que[i].r]^B[que[i].l-1];
Ans[que[i].id]^=Get(que[i].r)^Get(que[i].l-1);
}
for(int i=1;i<=m;i++)printf("%d\n",Ans[i]);
return 0;
}