luogu4168蒲公英(区间众数)
给定n个数,m个区间询问,问每个询问中的众数是什么。
题面很漂亮,大家可以去看一下。
对于区间众数,由于区间的答案不能由子区间简单的找出来,所以似乎不能用树形结构。
用分块的话,设一个区间[x, y],里面包含的最大连续的块的左端点是l,右端点是r。那么显然,这个区间的众数要么是[l, r]的众数,要么是[x, l)和(r, y]中的任意数。所以可以用\(f[i][j]\)表示第i到j块的众数是什么,同时用\(s[i][x]\)表示前i个块中x的出现次数。这样就可以做到\(n\sqrt{n}\)了。我的代码跑的算很快的。因为map没有sort快(废话)。
#include <cmath>
#include <cctype>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=4e4+5, sqrtm=2e2+5, INF=1e9;
int n, m, barlen, cntbar, a[maxn], bel[maxn], cnt[maxn];
int t[maxn], cntnum;
int s[sqrtm][maxn]; //前i个块x的出现次数
int f[sqrtm][sqrtm]; //第i到j块的众数是什么
void get(int &x){
x=0; char c; int flag=1;
for (c=getchar(); !isdigit(c); c=getchar());
for (x=c-48; c=getchar(), isdigit(c); )
x=x*10+c-48; x*=flag;
}
int main(){
get(n); get(m); barlen=sqrt(n); cntbar=1;
for (int i=0; i<n; ++i){
get(a[i]); t[i]=a[i];
bel[i]=i/barlen;
if (i&&bel[i]!=bel[i-1]) ++cntbar;
}
sort(t, t+n); cntnum=unique(t, t+n)-t;
for (int i=0; i<n; ++i)
a[i]=lower_bound(t, t+cntnum, a[i])-t;
for (int i=0; i<n; ++i) ++s[bel[i]][a[i]];
for (int i=1; i<cntbar; ++i) //n^1.5
for (int j=0; j<n; ++j) s[i][j]+=s[i-1][j];
int maxm=0, mcnt, q1, q2, l, r, tmp;
for (int i=0; i<cntbar; ++i){ //n^1.5
for (int j=0; j<n; ++j) cnt[j]=0;
mcnt=0;
for (int j=i*barlen; j<n; ++j){
++cnt[a[j]];
if (cnt[a[j]]>mcnt||(cnt[a[j]]==mcnt&&a[j]<maxm))
mcnt=cnt[a[j]], maxm=a[j];
if (bel[j]!=bel[j+1]) f[i][bel[j]]=maxm;
}
}
maxm=0;
for (int iq=0; iq<m; ++iq){
get(q1); get(q2);
q1=(q1+maxm-1)%n; q2=(q2+maxm-1)%n; mcnt=0;
if (q1>q2) swap(q1, q2);
if (bel[q1]==bel[q2]){
maxm=INF;
for (int i=q1; i<=q2; ++i) cnt[a[i]]=0;
for (int i=q1; i<=q2; ++i){
++cnt[a[i]];
if (cnt[a[i]]>mcnt||(cnt[a[i]]==mcnt&&a[i]<maxm))
mcnt=cnt[a[i]], maxm=a[i];
}
printf("%d\n", maxm=t[maxm]);
continue;
}
l=bel[q1]+1; r=bel[q2]-1;
if (l<=r) maxm=f[l][r], mcnt=s[r][maxm]-s[l-1][maxm];
//cnt表示两边需要暴力查找的数的出现个数
for (int i=q1; i==q1||bel[i]==bel[i-1]; ++i) cnt[a[i]]=0;
for (int i=q2; i==q2||bel[i]==bel[i+1]; --i) cnt[a[i]]=0;
for (int i=q1; i==q1||bel[i]==bel[i-1]; ++i) ++cnt[a[i]];
for (int i=q2; i==q2||bel[i]==bel[i+1]; --i) ++cnt[a[i]];
for (int i=q1; i==q1||bel[i]==bel[i-1]; ++i){
tmp=cnt[a[i]]+s[r][a[i]]-s[l-1][a[i]];
if (tmp>mcnt||(tmp==mcnt&&a[i]<maxm))
mcnt=tmp, maxm=a[i];
}
for (int i=q2; i==q2||bel[i]==bel[i+1]; --i){
tmp=cnt[a[i]]+s[r][a[i]]-s[l-1][a[i]];
if (tmp>mcnt||(tmp==mcnt&&a[i]<maxm))
mcnt=tmp, maxm=a[i];
}
printf("%d\n", maxm=t[maxm]);
}
return 0;
}