附加赛 D [奇技淫巧]

附加赛 D [奇技淫巧]

附加赛 D [奇技淫巧]_第1张图片

附加赛 D [奇技淫巧]_第2张图片

题解

显然,第一二种询问是等价的,可以用前缀异或和解决。

对于第三种询问,可以维护一个链表,一个数指向下一个与它相等的数的位置,并记下上一个与它相等的数的位置。

询问排序后(左端点为第一关键字,右端点为第二关键字),使用树状数组处理询问,树状数组的下标是同学的编号。当删除一个数的时候,只需要把这个数指向的下一个位置加入树状数组。

代码

#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;
}

你可能感兴趣的:(奇技淫巧,题解,链表)