原来我直接学的是假的莫队
原题:
Bob has a favorite number k and ai of length n. Now he asks you to answer m queries. Each query is given by a pair li and ri and asks you to count the number of pairs of integers i and j, such that l ≤ i ≤ j ≤ r and the xor of the numbers ai, ai + 1, ..., aj is equal to k.
1 ≤ n, m ≤ 100 000, 0 ≤ k ≤ 1 000 000, 0 ≤ ai ≤ 1 000 000
题意:
给定一个数列a[i],你可以通过异或前缀和求出s[i],每次求出[l-1,r]内s[i] xor s[j]=k的(i,j)的对数
模板题,先分块,左端点所在块为第一关键字,右端点为第二关键字排序
然后记录一个l和r,每次直接暴力让l和r走到查询的两端点即可
我之前一直以为块间跳转是当两端点中间有一个或多个块的时候加上中间的块的值
经过jjh和sqy大神的指点才知道原来分块就是指排序的时候分块,处理的时候暴力走就可以了
我学了假的分块
有一些细节需要注意,首先所有的操作都是建立在异或前缀和上的所以输入的时候要搞前缀和,而且算答案的时候l要-1
一般n<1e5求数对的个数一般会爆int,要注意longlong
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<vector> 7 using namespace std; 8 #define ll long long 9 int rd(){int z=0,mk=1; char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')mk=-1; ch=getchar();} 11 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 12 return z*mk; 13 } 14 struct dcd{int x,y,id;}b[110000]; 15 int n,m,k,a[110000]; 16 int blck; 17 ll cnt[1100000],ans[110000]; 18 ll bwl=0; 19 inline void ist(int x){ bwl+=cnt[a[x]^k],++cnt[a[x]];} 20 inline void dlt(int x){ --cnt[a[x]],bwl-=cnt[a[x]^k];} 21 bool cmp(dcd x,dcd y){ return(x.x/blck==y.x/blck)?(x.y<y.y):(x.x/blck<y.x/blck);} 22 int main(){//freopen("ddd.in","r",stdin); 23 cin>>n>>m>>k; blck=(int)sqrt(n*1.0); 24 for(int i=1;i<=n;++i) a[i]=rd(),a[i]^=a[i-1]; 25 for(int i=1;i<=m;++i) b[i].x=rd(),b[i].y=rd(),b[i].id=i; 26 sort(b+1,b+m+1,cmp); 27 int l=1,r=0; cnt[0]=1; 28 for(int i=1;i<=m;++i){ 29 while(l<b[i].x) dlt(l-1),++l; 30 while(l>b[i].x) l--,ist(l-1); 31 while(r<b[i].y) ist(++r); 32 while(r>b[i].y) dlt(r--); 33 ans[b[i].id]=bwl; 34 } 35 for(int i=1;i<=m;++i) printf("%I64d ",ans[i]); 36 return 0; 37 }