分块
吸了氧气才过
强制在线区间众数,具体见hzwer的解题报告(右转Baidu)
先把数字离散化
然后对于每个数字开个动态数组存出现的位置
每次对完整块的众数和不完整块的所有数在动态数组中进行查询,答案必定在它们之中
code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> #include<map> #include<cctype> using namespace std; inline int Int(){ char c=getchar(); int x=0; while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x; } inline int min(int &a,int &b) {return a<b ?a:b;} int n,m,ans,mxd,cnt,_blo,blo[40002],a[40002],f[210][210],mp[40002],ct[40002]; vector <int> v[40002]; map <int,int> Map; inline void pre(int x){ //预处理整块的区间众数 memset(ct,0,sizeof(ct)); int mx=0,t=0; for(int i=(x-1)*_blo+1;i<=n;++i){ ++ct[a[i]]; if(ct[a[i]]>mx||(mx==ct[a[i]]&&mp[a[i]]<mp[t])) t=a[i],mx=ct[a[i]]; f[x][blo[i]]=t; //第x块到blo[i]块之间的众数 } } inline int find(int l,int r,int k){ //区间内出现的次数 return upper_bound(v[k].begin(),v[k].end(),r)-lower_bound(v[k].begin(),v[k].end(),l); } inline void query(int l,int r){ ans=f[blo[l]+1][blo[r]-1]; mxd=find(l,r,ans); //完整块的众数 for(int i=min(blo[l]*_blo,r);i>=l;--i){ //对于不完整的块,对所有数暴力查询 int t=find(l,r,a[i]); if(t>mxd||(t==mxd&&mp[a[i]]<mp[ans])) mxd=t,ans=a[i]; } if(blo[l]==blo[r]) return ; for(int i=(blo[r]-1)*_blo+1;i<=r;++i){ int t=find(l,r,a[i]); if(t>mxd||(t==mxd&&mp[a[i]]<mp[ans])) mxd=t,ans=a[i]; } } int main(){ n=Int(); m=Int(); _blo=sqrt(n); int q1,q2; for(int i=1;i<=n;++i){ a[i]=Int(); if(!Map[a[i]]) Map[a[i]]=++cnt,mp[cnt]=a[i]; a[i]=Map[a[i]]; //离散化 v[a[i]].push_back(i); blo[i]=(i-1)/_blo+1; } for(int i=1;i<=blo[n];++i) pre(i); for(int i=1;i<=m;++i){ q1=Int(); q2=Int(); q1=(q1+ans-1)%n+1,q2=(q2+ans-1)%n+1; if(q1>q2) swap(q1,q2); query(q1,q2); ans=mp[ans]; printf("%d ",ans); } return 0; }