1. 程式人生 > >luogu4168蒲公英(區間眾數)

luogu4168蒲公英(區間眾數)

由於 樹形結構 -i esp names 不能 暴力 const uniq

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; }

luogu4168蒲公英(區間眾數)