Link
Solve
本题是非常经典的在线求区间众数问题。因为众数不具有区间可加性(已知([x,y])和([y+1,z])的众数,不能直接得到([x,z])的众数),所以用树状数组或者线段树维护就特别难,我们考虑分块来做。
我们把序列分成(T)块,每块长度(L=N/T)。
对于每个询问([l,r]),设(l)处于第(p)块,(r)处于第(q)块,我们可以把([l,r])分成三个部分。
1.开头不足一段([l,L))
2.第(p+1)~(q-1)块的区间([L,R])
3.结尾不足一段((L,R])
显然,序列在区间([l,r])上的众数只可能来自于以下两种情况
1.区间([L,R])的众数
2.出现在([l,L))和((R,r])之间的数
我们先预处理出义"段边界"为端点的区间([L,R])的众数,然后开(N)个(vextor)保存数值(a_i)所在的位置(离散后)。
对于每个询问扫描([l,L)) 与((R,r])中的每个数(x),在对应的(vector)中二分查找即可得到(x)在([l,r])中出现的次数,从而更新答案,
这个算法的时间为(O(NT+NM/T ast log N)),空间为(O(N^2))。应取(T=sqrt{NlogN}),使得整个算法时间复杂度在(O(Nsqrt{NlogN}))级别。
代码细节比较多,调了一个早上
#include<cstdio>
#include<vector>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
const int maxn=40005,maxt=205;
int N,t,M,p[maxt][maxt],m,L[maxt],R[maxt],pos[maxn],cnt[maxn],last,up[maxn];
vector <int> Q[maxn];
struct AS{
int x,id,color;
}a[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
bool cmp1(AS A,AS B){return A.x<B.x;}
bool cmp2(AS A,AS B){return A.id<B.id;}
int get(int l,int r,int x){
return upper_bound(Q[x].begin(),Q[x].end(),r)-lower_bound(Q[x].begin(),Q[x].end(),l);
}
int query(int l,int r){
int max_x=0,num=0,res;
if(pos[l]+1<pos[r]){max_x=get(l,r,p[pos[l]+1][pos[r]-1]),num=p[pos[l]+1][pos[r]-1];}
for(int i=l;i<=R[pos[l]];i++){
res=get(l,r,a[i].color);
if(res>max_x||(res==max_x&&a[i].color<num)){max_x=res;num=a[i].color;}
}
if(pos[l]!=pos[r])
for(int i=L[pos[r]];i<=r;i++){
res=get(l,r,a[i].color);
if(res>max_x||(res==max_x&&a[i].color<num)){max_x=res;num=a[i].color;}
}
return num;
}
int main(){
freopen("P4168.in","r",stdin);
freopen("P4168.out","w",stdout);
N=read();M=read();
for(int i=1;i<=N;i++)a[i].x=read(),a[i].id=i;
sort(a+1,a+1+N,cmp1);
for(int i=1;i<=N;i++){
if(a[i].x!=a[i-1].x)++m,up[m]=a[i].x;
a[i].color=m;
}
sort(a+1,a+1+N,cmp2);
for(int i=1;i<=N;i++)Q[a[i].color].push_back(i);
for(int i=1;i<=m;i++)Q[i].push_back(N+1);
t=sqrt(N);
for(int i=1;i<=t;i++){
L[i]=(i-1)*sqrt(N)+1;
R[i]=i*sqrt(N);
}
if(R[t]<N){t++;L[t]=R[t-1]+1;R[t]=N;}
for(int i=1;i<=t;i++){
for(int j=L[i];j<=R[i];j++){pos[j]=i;}
}
for(int i=1;i<=t;i++){
memset(cnt,0,sizeof cnt);int max_x=0,num=0;
for(int j=L[i];j<=N;j++){
cnt[a[j].color]++;
if(cnt[a[j].color]>max_x||(cnt[a[j].color]==max_x&&a[j].color<num)){
max_x=cnt[a[j].color];num=a[j].color;
}
p[i][pos[j]]=num;
}
}
while(M--){
int l=read(),r=read();
l=(l+last-1)%N+1,r=(r+last-1)%N+1;
if(l>r)swap(l,r);
last=up[query(l,r)];
printf("%d
",last);
}
return 0;
}