题链:http://codeforces.com/contest/617/problem/E
题意:对于一个区间[L,R],问有多少子区间[l,r],a[l] ^ a[l+1] ^ a[l+2] ^ ... ^ a[r] == k ?
思路:首先,先解决求 a[l] ^ a[l+1] ^ a[l+2] ^ ... ^ a[r] , 这里用前缀思想,即pre[l-1]^pre[r]。现在,我们维护一个num数组,num[k]代表pre[i]==k的个数。考虑加入一个数,那么,答案要先加上num[k^pre[i]],然后num[pre[i]]++;考虑删除一个数,那么先num[pre[i]]--,然后答案减去num[k^pre[i]]。注意一个询问区间[ql,qr],要变为[ql-1,qr]。感性的理解就是前缀和,理性的理解就是要加上以ql为左端点的子区间,因为以ql为左端点的子区间异或和时,异或的是pre[ql-1]。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+10;
int n,m,k,a[N];
struct node{
int l,r,id;
}q[N];
int base,belong[N];
int num[N<<1],now=0;
ll ans[N],sum=0;
void del(int x){
--num[a[x]];
sum-=num[k^a[x]];
}
void add(int x){
sum+=num[k^a[x]];
++num[a[x]];
}
bool cmp(node a,node b){
return (belong[a.l]^belong[b.l])?belong[a.l]<belong[b.l]:((belong[a.l]&1)?a.r<b.r:a.r>b.r);
}
int main(void){
scanf("%d%d%d",&n,&m,&k);
base=ceil(sqrt(1.0*n));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i]^=a[i-1];
belong[i]=i/base;
}
for(int i=1;i<=m;i++)
scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+1+m,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++){
int ql=q[i].l-1,qr=q[i].r;
while(l<ql) del(l++);
while(l>ql) add(--l);
while(r>qr) del(r--);
while(r<qr) add(++r);
ans[q[i].id]=sum;
}
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}