bzoj2821
大胆猜想分块:预处理每块值的桶,及 f [ i ] [ j ] f[i][j] f[i][j]表示第 i − j i-j i−j块的答案。
复杂度存疑,遂证明之:预处理 O ( n n ) O(n\sqrt n) O(nn),询问散块最多只涉及 2 n 2\sqrt n 2n个值,答案=这 2 n 2\sqrt n 2n在散整块中出现情况+ f [ b e l l + 1 ] [ b e l r − 1 ] f[bel_l+1][bel_r-1] f[bell+1][belr−1],复杂度同样为 O ( n n ) O(n\sqrt n) O(nn)。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=318;
int n,c,m,blk,ql[M],qr[M],cnt,tim,ans;
int a[M],f[M][N],g[M][M],vs[N],cot[N],q[N],tot;
int main(){
int i,j,k,v,t,lim,x,y,l,r;
scanf("%d%d%d",&n,&c,&m);
blk=sqrt(n);cnt=(n-1)/blk+1;
for(i=1;i<=n;++i) scanf("%d",&a[i]);
for(i=1;i<=cnt;++i){
ql[i]=(i-1)*blk+1;qr[i]=(i^cnt)?i*blk:n;
for(j=ql[i],lim=qr[i];j<=lim;++j)
for(k=i,v=a[j];k<=cnt;++k) f[k][v]++;
}
for(i=1;i<=cnt;++i){
for(v=0,j=i;j<=cnt;++j){
for(k=ql[j],lim=qr[j];k<=lim;++k){
cot[a[k]]++;
if(!(cot[a[k]]&1)) v++;else if(cot[a[k]]>1) v--;
}
g[i][j]=v;
}
memset(cot,0,sizeof(cot));
}
for(tim=cnt;m;--m){
scanf("%d%d",&x,&y);
x=(x+ans)%n+1;y=(y+ans)%n+1;if(x>y) swap(x,y);
l=(x-1)/blk+1;r=(y-1)/blk+1;tim++;tot=ans=0;
for(lim=min(qr[l],y),i=x;i<=lim;++i){
if(vs[a[i]]!=tim) q[++tot]=a[i],vs[a[i]]=tim;
cot[a[i]]++;
}
if(l^r)
for(i=ql[r];i<=y;++i){
if(vs[a[i]]!=tim) q[++tot]=a[i],vs[a[i]]=tim;
cot[a[i]]++;
}
if(l+2<=r){
ans=g[l+1][r-1];
for(i=1;i<=tot;++i){
x=f[r-1][q[i]]-f[l][q[i]];y=cot[q[i]]&1;
if(!x) ans+=(y?0:1);
else if(!(x&1)) ans-=(y?1:0);
else ans+=(y?1:0);
}
}else for(i=1;i<=tot;++i) ans+=(cot[q[i]]&1)?0:1;
for(i=1;i<=tot;++i) cot[q[i]]=0;
printf("%d\n",ans);
}
return 0;
}
bzoj2724
维护区间众数,和上面十分类似