一道经典的分块例题,因为我们通过观察可知,区间众数要不就是中间所有块上的答案,要不就是两边小块上出现过的值
因此我们可以分块处理,只要预处理块与块之间的答案即可,因为本题没有修改操作
另外这题比较卡常,块的大小要先算好,不过也有复杂度更低的算法
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<string> #include<map> #include<vector> using namespace std; typedef long long ll; const int N=1e6+10; const int mod=1e9+7; vector<int> g[N]; int d[2001][2001]; int c[N],a[N]; int n,m; int block; int cnt[N]; void init(){ int l,r; for(l=1;l<=n;l+=block){ int res=0; memset(cnt,0,sizeof cnt); for(r=l;r<=n;r++){ cnt[a[r]]++; if(cnt[a[r]]>cnt[res]||cnt[a[r]]==cnt[res]&&a[r]<res) res=a[r]; if(r%block==0||r==n) d[(l-1)/block+1][(r-1)/block+1]=res; } } } int find(int l,int r,int x){ return upper_bound(g[x].begin(),g[x].end(),r)-lower_bound(g[x].begin(),g[x].end(),l); } int query(int l, int r){ int ans = 0; int B=block; int idl = (l-1)/B+1, idr = (r-1)/B+1; if(idl+1 < idr) ans = d[idl+1][idr-1]; int n = find(l,r,ans), n1; if(idl==idr){ for(int i=l;i<=r;i++){ n1 = find(l,r,a[i]); if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1; } } else{ for(int i=l;i<=idl*B;i++){ n1 = find(l,r,a[i]); if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1; } for(int i=(idr-1)*B+1;i<=r;i++){ n1 = find(l,r,a[i]); if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1; } } return c[ans]; } int main(){ cin>>n>>m; int i; block=max(1,(int)(n/sqrt(m*log2(n)))); for(i=1;i<=n;i++){ scanf("%d",&a[i]); c[i]=a[i]; } sort(c+1,c+1+n); for(i=1;i<=n;i++){ a[i]=lower_bound(c+1,c+1+n,a[i])-c; g[a[i]].push_back(i); } init(); int last=0; int l,r; while(m--){ scanf("%d%d",&l,&r); l = (l+last-1)%n + 1; r = (r+last-1)%n + 1; if(l>r) swap(l,r); last=query(l,r); printf("%d\n",last); } }