[CQOI2018]异或序列 (莫队,异或前缀和)

题目链接


Solution

有点巧的莫队.
考虑到区间 ([L,R]) 的异或和也即 (sum[L-1]~igoplus~sum[R]) ,此处(sum)即为异或前缀和.
然后如何考虑异或和为 (k) ?
我们做完前缀和后,可以发现对于(sum[i])这个起点,异或上(kigoplus{sum[i]})则可以异或成(k).
且由于 (kleq{100000}) ,所以可以开一个数组记录每一个异或值的出现次数.
然后就可以 (O(1)) 修改了,套个莫队即可.

Code

#include<bits/stdc++.h>
#define N 100001
#define in(x) x=read()
#define del(x) js[a[x]]--;ans-=js[a[x]^k];
#define add(x) ans+=js[a[x]^k];js[a[x]]++;
using namespace std;

struct sj{int l,r,id;}q[N];
int js[N],pos[N],Ans[N],a[N],n,m,k;
int L,R,ans,sz;
int read()
{
    char ch=getchar();int f=1,w=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
    return f*w;
}

bool cmp(sj x,sj y)
{
    if(pos[x.l]==pos[y.l])return pos[x.r]<pos[y.r];
    return pos[x.l]<pos[y.l];
}

int main()
{
    in(n),in(m),in(k); sz=sqrt(n);
    for(int i=1;i<=n;i++)
    {int x; in(x); a[i]=a[i-1]^x;pos[i]=i/*/sz*/;}
    for(int i=1;i<=m;i++)
        in(q[i].l),in(q[i].r),q[i].id=i;
    sort(q+1,q+m+1,cmp);
    js[0]=1; ans=0; L=1;
    for(int i=1;i<=m;i++)
    {
        while(L>q[i].l){L--;add(L-1);}
        while(L<q[i].l){del(L-1);L++;}
        while(R<q[i].r){R++;add(R);}
        while(R>q[i].r){del(R);R--;}
        Ans[q[i].id]=ans;
    }
    for(int i=1;i<=m;i++)
    cout<<Ans[i]<<endl;
}