转化题意:
给n个整数,给一个值k,m个询问,每个询问给出一个区间,求区间里有多少对数异或为k
注意到n个整数的值比较小,可以用桶存值的
我们用前缀异或和即可实现区间转化为数(满足区间减法即可
1≤n,m≤1e5,0≤k,值的大小≤1e5,
然后用莫队实现n sqrt(n),空间为o(值的大小)
操作:
分块排序,每次移动区间时
添加为存数并更新答案o(1)
删除为更新答案并删数o(1)
#include<bits/stdc++.h> #define LL long long #define IL inline using namespace std; const int N=100005; int a[N],b[N]; int n,m,k; struct modui{ int l,r,id; }q[N]; int cnt; LL ans[N],ans0; bool cmp(modui a,modui b){ return a.l/cnt^b.l/cnt?a.l<b.l:a.r<b.r; } IL void add(int p){ ans0+=b[a[p]^k]; b[a[p]]++; } IL void del(int p){ b[a[p]]--; ans0-=b[a[p]^k]; } int main(){ scanf("%d%d%d",&n,&m,&k); cnt=sqrt(n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=n;i++){ a[i]^=a[i-1]; } for(int i=1;i<=m;i++){ scanf("%d%d",&q[i].l,&q[i].r); q[i].l--; q[i].id=i; } sort(q+1,q+1+m,cmp); register int l=1,r=0; for(int i=1;i<=m;i++){ while(l<q[i].l)del(l++); while(l>q[i].l)add(--l); while(r<q[i].r)add(++r); while(r>q[i].r)del(r--); ans[q[i].id]=ans0; } for(int i=1;i<=m;i++){ printf("%lld ",ans[i]); } return 0; }