洛谷4462 || BZOJ5301 [Cqoi2018]异或序列【莫队】

Time Limit: 10 Sec
Memory Limit: 512 MB

Description

已知一个长度为 n 的整数数列 a[1],a[2],…,a[n] ,给定查询参数 l、r ,问在 [l,r] 区间内,有多少连续子序列满足异或和等于 k 。
也就是说,对于所有的 x,y (l≤x≤y≤r),能够满足a[x]^a[x+1]^…^a[y]=k的x,y有多少组。

Input

输入文件第一行,为3个整数n,m,k。
第二行为空格分开的n个整数,即ai,a2,….an。
接下来m行,每行两个整数lj,rj,表示一次查询。
1≤n,m≤105,O≤k,ai≤105,1≤lj≤rj≤n

Output

输出文件共m行,对应每个查询的计算结果。


题目分析

对于连续子序列异或和等于k
很容易想到前缀异或和
对于没有区间相加性的询问也很好想到莫队

那么就按照莫队的思想
若当前更新操作为增加,cnt[x]++
则有答案总数sum+=cnt[k^x]
对于删除也是同理

不过要注意的是
因为维护数量时用到了前缀和
所以每次维护更新时要用L-1


#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}

const int maxn=500010;
int n,m,k;
int L=1,R=0,t;
int xr[maxn],cnt[maxn];
struct node{int ll,rr,num;}q[maxn];
int ans[maxn],sum; 
bool cmp(node a,node b){return (a.ll/t)==(b.ll/t) ?a.rr<b.rr :(a.ll/t)<(b.ll/t);}

void add(int x)
{
    cnt[x]++;
    sum+=cnt[k^x];
}

void del(int x)
{
    cnt[x]--;
    sum-=cnt[k^x];
}

int main()
{
    n=read();m=read();k=read(); 
    t=sqrt(n); cnt[0]=1;//记得初始化cnt[0]=1
    for(int i=1;i<=n;++i)
    {
        int x=read();
        xr[i]=xr[i-1]^x;
    }
    for(int i=1;i<=m;++i)
    q[i].ll=read(),q[i].rr=read(),q[i].num=i;

    sort(q+1,q+1+m,cmp);
    for(int i=1;i<=m;++i)
    {
        while(R<q[i].rr) add(xr[++R]);
        while(R>q[i].rr) del(xr[R--]);
        while(L<q[i].ll) del(xr[L-1]),L++;
        while(L>q[i].ll) add(xr[--L-1]);//记得更新是L-1
        ans[q[i].num]=sum;
    }
    for(int i=1;i<=m;++i)
    printf("%d\n",ans[i]);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/niiick/article/details/80340979