标签:std pen etc ret || 级别 更新 区间 个数
本题是非常经典的在线求区间众数问题。因为众数不具有区间可加性(已知\([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(N\sqrt{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\n",last);
}
return 0;
}
标签:std pen etc ret || 级别 更新 区间 个数
原文地址:https://www.cnblogs.com/martian148/p/13884192.html