这是一道经典的分块题——用分块求区间众数。分块在线的时间复杂度为O( q sqrt(n) ),离线为O( n sqrt(n) )。
分块可以进行区间操作,像求区间最值,区间和,区间修改等等。适用范围:分块>线段树>树状数组。
用分块进行区间操作时,中间的完整的块可以通过预处理来完成,然后两头的就暴力for一下。
下面是AC代码:
#include<bits/stdc++.h> #define M 50500 #define mc 500 #define R register int using namespace std; struct Violet{int num,x,w;}a[M]; //num 表示输入顺序 //x 表示离散化之后的数 //w 表示原数 int block,n,m,answer,tot; int s[M],sum[mc][M],ans[mc][mc],belong[M],color[M]; //s[i] 是离散化之后的数与原数的映射 //sum[i][j] 是离散化后每个数在每一块中的前缀和 //ans[i][j] 表示第i-j块的众数 //belong[i] 第i个数所在的块数 //color[i] 表示离散化之后数i出现的次数 void first(); void getsum(); void getans(); void sovle(); void query(int,int); bool cmp1(Violet,Violet); bool cmp2(Violet,Violet); int main(){ ios::sync_with_stdio(0); first(); getsum(); getans(); sovle(); return 0; } void first(){ cin>>n>>m; block=sqrt(n); for(R i=1;i<=n;++i) cin>>a[i].w,a[i].num=i; sort(a+1,a+n+1,cmp1); for(R i=1;i<=n;++i){ if(a[i].w!=a[i-1].w){ s[++tot]=a[i].w; a[i].x=tot; } else a[i].x=a[i-1].x; } sort(a+1,a+n+1,cmp2); } void getsum(){ for(R i=1;i<=n;++i){ belong[i]=i/block; ++sum[belong[i]][a[i].x]; } for(R i=0;i<=belong[n];++i) for(R j=1;j<=tot;++j) sum[i][j]+=sum[i-1][j]; } void getans(){ for(R i=0;i<=belong[n];++i){ int be=i*block,now=0; if(!be) be=1; for(R j=be;j<=n;++j){ if((++color[a[j].x] > color[now]) || (color[a[j].x] == color[now] && a[j].x<now)) now=a[j].x; ans[i][belong[j]]=now; } for(R j=be;j<=n;++j) --color[a[j].x]; } } void sovle(){ int l,r; for(R i=1;i<=m;++i){ cin>>l>>r; l=(l+s[answer]-1)%n+1,r=(r+s[answer]-1)%n+1; if(l>r) query(r,l); else query(l,r); } } void query(int x,int y){ int l=x/block+1,r=y/block-1; if(r-l<=1){ answer=0; for(R i=x;i<=y;++i) if((++color[a[i].x] > color[answer]) || (color[a[i].x] == color[answer] && a[i].x < answer)) answer=a[i].x; for(R i=x;i<=y;++i) --color[a[i].x]; printf("%d\n",s[answer]); return; } else{ answer=ans[l][r]; for(R i=x;i<=l*block-1;++i) if(++color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] > color[answer]+sum[r][answer]-sum[l-1][answer]) answer=a[i].x; else if(color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] == color[answer]+sum[r][answer]-sum[l-1][answer] && a[i].x < answer) answer=a[i].x; for(R i=(r+1)*block;i<=y;++i) if(++color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] > color[answer]+sum[r][answer]-sum[l-1][answer]) answer=a[i].x; else if(color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] == color[answer]+sum[r][answer]-sum[l-1][answer] && a[i].x < answer) answer=a[i].x; for(R i=x;i<=l*block-1;++i) --color[a[i].x]; for(R i=(r+1)*block;i<=y;++i) --color[a[i].x]; printf("%d\n",s[answer]); return; } } bool cmp1(Violet x,Violet y){return x.w<y.w;} bool cmp2(Violet x,Violet y){return x.num<y.num;}