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

题目链接


Solution

有点巧的莫队.
考虑到区间 \([L,R]\) 的异或和也即 \(sum[L-1]~\bigoplus~sum[R]\) ,此处\(sum\)即为异或前缀和.
然后如何考虑异或和为 \(k\) ?
我们做完前缀和后,可以发现对于\(sum[i]\)这个起点,异或上\(k\bigoplus{sum[i]}\)则可以异或成\(k\).
且由于 \(k\leq{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;
}

posted @ 2018-10-25 16:30  Kevin_naticl  阅读(280)  评论(0编辑  收藏  举报