P4462 [CQOI2018]异或序列

思路

把序列求前缀异或和一下
问题转变成了[l,r]中有多少个数对(x,y)的异或和为k
然后莫队就好了

代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    int n,m,k,a[100100],belong[100100],sz,num,L,R,ans[100100],barrel[2001000],sum=0;
    struct Query{
        int l,r,id;
        bool operator < (const Query &b){
            return (belong[l]==belong[b.l])?r<b.r:belong[l]<belong[b.l];
        }
    }Q[100100];
    void init(void){
        sz=sqrt(n);
        num=n/sz;
        if(n%sz)
            num++;
        for(int i=1;i<=n;i++)
            belong[i]=i/sz+1;
    }
    void moveL(int opt){
        if(opt==1){
            barrel[a[L]]--;
            sum-=barrel[k^a[L]];
            L++;
        }
        else{
            L--;
            sum+=barrel[k^a[L]];
            barrel[a[L]]++;
        }
    }
    void moveR(int opt){
        if(opt==1){
            R++;
            sum+=barrel[k^a[R]];
            barrel[a[R]]++;
        }
        else{
            barrel[a[R]]--;
            sum-=barrel[k^a[R]];
            R--;
        }
    }
    int main(){
        scanf("%d %d %d",&n,&m,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),a[i]^=a[i-1];
        init();
        for(int i=1;i<=m;i++){
            scanf("%d %d",&Q[i].l,&Q[i].r);
            Q[i].l--;
            Q[i].id=i;
        }
        sort(Q+1,Q+m+1);
        L=1;
        R=0;
        sum=0;
        for(int i=1;i<=m;i++){
            while(L<Q[i].l)
                moveL(1);
            while(L>Q[i].l)
                moveL(-1);
            while(R<Q[i].r)
                moveR(1);
            while(R>Q[i].r)
                moveR(-1);
            ans[Q[i].id]=sum;
        }
        for(int i=1;i<=m;i++)
            printf("%d
",ans[i]);
        return 0;
    }