在线询问区间众数,传统的分块(记录块间众数和每个权值的出现次数)做法被卡空间(分块用的空间是O(块数*(块数+权值种类数))),因此考虑去掉出现次数较小的数,只用分块维护出现次数较大的数。设K为分界线,用原来的分块维护原序列中出现次数>K的数组成的部分,而出现次数<=K的数,可以通过记录一个数前面第1~K个相同的数的位置,用线段树维护,线段树查询时利用单调性单次询问可以做到$O(k+logn)$,不会成为瓶颈。
当K取$O(n^{1/4})$时,时间复杂度仍是$O(qsqrt{n})$,空间复杂度为$O(n^{5/4})$
#include<bits/stdc++.h> char buf[65555],*ptr=buf+65536; int g(){ if(ptr-buf==65536)fread(buf,1,65536,stdin)[buf]=0,ptr=buf; return *ptr++; } int __(){ int x=0,c=g(); while(c<48)c=g(); while(c>47)x=x*10+c-48,c=g(); return x; } int _(){ if(ptr-buf>65500)return __(); int x=0,c=*ptr++; while(c<48)c=*ptr++; while(c>47)x=x*10+c-48,c=*ptr++; return x; } typedef unsigned short u16; int n,m; int v0[60007],vs[60007],B,v1[60007],vp1=0; u16 bc[365][6677],ws[60007],t[60007],rid[60007],bb[365][365],pv[60007],pw[60007]; int ls[405],rs[405]; u16 tr[131111][7]; int max(int a,int b){return a>b?a:b;} int get(int l,int r){ int p=0; for(int a=l+65535,b=r+65537;b-a!=1&&p<7;a>>=1,b>>=1){ if(~a&1)while(p<7&&tr[a^1][p]>=l)++p; if(b&1)while(p<7&&tr[b^1][p]>=l)++p; } return p+1; } int main(){ n=_();m=_(); for(int i=1;i<=n;++i)vs[i]=v0[i]=_(); std::sort(vs+1,vs+n+1); for(int i=1;i<=n;++i)v0[i]=std::lower_bound(vs+1,vs+n+1,v0[i])-vs; for(int i=1;i<=n;++i){ int x=v0[i]; pv[i]=pw[x]; pw[x]=i; for(int j=0,z=pv[i];j<7;++j)tr[i+65536][j]=z,z=pv[z]; } for(int i=65535;i;--i){ int a=i<<1,b=a^1; for(int j=0;j<7;++j)tr[i][j]=max(tr[a][j],tr[b][j]); } for(int i=1;i<=n;++i)++t[v0[i]]; int idp=0; for(int i=1;i<=n;++i)if(t[i]>8)rid[i]=++idp; for(int i=1;i<=n;++i)if(rid[v0[i]]){ v1[++vp1]=rid[v0[i]]; v0[i]=vp1; }else v0[i]=v0[i-1]; for(int i=1;i<=n;++i)t[i]=0; n=vp1; for(B=1;n/B>362;++B); for(int l=1,r=B,c=1;l<=n;l+=B,r+=B,++c){ if(r>n)r=n; ls[c]=l;rs[c]=r; for(int i=ls[c];i<=rs[c];++i)ws[i]=c; for(int b=c;b;--b){ bb[c][b]=bb[c][b+1]; for(int i=ls[b];i<=rs[b];++i)if(v1[i]){ int x=++bc[c][v1[i]]; if(x>bc[c][bb[c][b]])bb[c][b]=v1[i]; } } } int la=0; while(m--){ int L=_()^la,R=_()^la; int a0=get(L,R); L=v0[L-1]+1;R=v0[R]; int l=ws[L],r=ws[R]; if(a0<8)la=a0; else if(r-l<=1){ la=a0; for(int i=L;i<=R;++i){ int x=v1[i]; if(x&&++t[x]>la)la=t[x]; } for(int i=L;i<=R;++i)--t[v1[i]]; }else{ --r,++l; int mx=bb[r][l]; u16*s1=bc[r],*s2=bc[l-1]; for(int i=rs[l-1];i>=L;--i){ int x=v1[i]; int t1=++t[x]+s1[x]-s2[x]; if(t1>t[mx]+s1[mx]-s2[mx])mx=x; } for(int i=ls[r+1];i<=R;++i){ int x=v1[i]; int t1=++t[x]+s1[x]-s2[x]; if(t1>t[mx]+s1[mx]-s2[mx])mx=x; } la=max(a0,t[mx]+bc[r][mx]-bc[l-1][mx]); for(int i=rs[l-1];i>=L;--i)--t[v1[i]]; for(int i=ls[r+1];i<=R;++i)--t[v1[i]]; } printf("-%d ",la); } return 0; }