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