传送门:http://codeforces.com/contest/617/problem/E
题意:
给出一系列数,对每个查询区间,计算有多少个子区间异或为k。
思路:
可以先预处理异或前缀,一个区间[L,R]的异或值=sum[R]^sum[L-1];
如果当前区间是[a,b],加一个右端点b+1,那么这个b+1的贡献就是[a,b]区间内有多少个sum[x]=sum[b+1]^k
那么我们可以每次记录num[sum[x]]即num[sum[b+1]^k],并记录num[sum[b+1]]++,同理左区间。
那么我们就可以使用莫队算法。
#include <iostream> #include <cstdio> #include <algorithm> typedef long long ll; using namespace std; const int maxn = 1<<20; ll a[maxn]; ll sum = 0, ans[maxn]; int k,B = 233,cnt[maxn]; #define bel(x) ((x-1)/B +1) struct node{ int id,l,r; }q[maxn]; bool cmp (node a, node b) { if(bel(a.l) == bel(b.l)) return a.r < b.r; return bel(a.l) < bel(b.l); } void add(int x) { sum += cnt[x ^ k]; cnt[x] ++; } void del (int x) { cnt[x] --; sum -= cnt[ x^k ]; } int main(){ int n,m; scanf("%d%d%d",&n,&m,&k); for(int i=1; i<=n; i++) { scanf("%I64d",&a[i]); a[i] ^= a[i-1]; } for(int i = 1; i <= m; i++) { scanf("%d%d",&q[i].l,&q[i].r); q[i].id = i; } sort(q+1, q+m+1, cmp); ll ql = 1,qr = 0; cnt[0] = 1; for(int i=1; i<=m; i++) { while(ql < q[i].l) del(a[ql-1]),ql++; while(ql > q[i].l) ql--,add(a[ql-1]); while(qr > q[i].r) del (a[qr--]); while(qr < q[i].r) add (a[++qr]); ans[q[i].id] = sum; } for(int i=1; i<=m; i++) printf("%I64d\n",ans[i]); return 0; }