BZOJ4241 歷史研究 分塊

2022-05-20 16:18:40 字數 1610 閱讀 8263

ioi國歷史研究的第一人——joi教授,最近獲得了乙份被認為是古代ioi國的住民寫下的日記。joi教授為了通過這份日記來研究古代ioi國的生活,開始著手調查日記中記載的事件。

日記中記錄了連續n天發生的時間,大約每天發生一件。

事件有種類之分。第i天(1<=i<=n)發生的事件的種類用乙個整數xi表示,xi越大,事件的規模就越大。

joi教授決定用如下的方法分析這些日記:

現在你被要求製作乙個幫助教授分析的程式,每次給出分析的區間,你需要輸出重要度的最大值。

第一行兩個空格分隔的整數n和q,表示日記一共記錄了n天,詢問有q次。

接下來一行n個空格分隔的整數x1...xn,xi表示第i天發生的事件的種類

接下來q行,第i行(1<=i<=q)有兩個空格分隔整數ai和bi,表示第i次詢問的區間為[ai,bi]。

輸出q行,第i行(1<=i<=q)乙個整數,表示第i次詢問的最大重要度

5 59 8 7 8 9

1 23 4

4 41 4

2 4988

1616

1<=n<=10^5

1<=q<=10^5

1<=xi<=10^9 (1<=i<=n)

題解:第一眼看題都感覺是莫隊吧?然而聽說這題卡莫隊。

這題的本質是乙個帶權的區間眾數問題,如果你會做區間眾數,那麼這道題也不難(當然不會做也無所謂)。

先分塊,假設[a,b]是[l,r]中一段連續的整塊,那麼[l,r]中的帶權眾數∈([a,b]中的眾數 u [l,a)和(b,r]中的所有數)。那麼我們預處理出任意兩個塊(a,b)之間的帶權眾數(方法:列舉左邊的塊,在暴力掃一遍右邊的所有塊,用桶記錄一下,維護個最大值),以及[1,a]中所有數出現的次數。處理詢問時,先直接拿出中間整塊的眾數,再列舉兩邊小塊的所有數即可。

#include #include #include #include #include using namespace std;

typedef long long ll;

const int maxn=100010;

int n,m,nm,b;

ll ans;

struct node

num[maxn];

int v[maxn],ref[maxn],st[maxn],s[400][maxn];

ll mx[400][400];

bool cmp(node a,node b)

int main()

for(i=0;ifor(i=1;i*bfor(i=0;i*bmemset(st,0,sizeof(st));

} for(i=1;i<=m;i++)

ans=mx[c+1][d-1];

for(j=a;jfor(j=d*b;j<=b;j++) st[v[j]]=s[d-1][v[j]]-s[c][v[j]];

for(j=a;jfor(j=d*b;j<=b;j++) st[v[j]]++,ans=max(ans,(ll)st[v[j]]*ref[v[j]]);

for(j=a;jfor(j=d*b;j<=b;j++) st[v[j]]=0;

printf("%lld\n",ans);

} return 0;

}

bzoj4241 歷史研究 分塊

popoqqq大神的題解 分塊後,處理出mx i j 表示第i塊到第j塊的答案,cnt i j 表示前i塊數字j的個數,注意先離散化。然後每次查詢,把塊外的部分單獨處理,塊內的部分直接寫答案就可以了。include include include include include include de...

bzoj 4241 歷史研究 分塊

首先分成n 0.5塊,然後答案顯然是中間一整段的最大值,或者是兩端零星的部分。那麼可以得到f i j 表示第i塊到第j塊的答案 然後就需要快速求出零星部分出現的次數,用乙個字首和s i j 表示在前i塊中j出現的次數。離散化搞一搞。好像莫隊也是可以的把。ac 如下 include include i...

bzoj4241 歷史研究 分塊

傳送門 ioi國歷史研究的第一人 joi教授,最近獲得了乙份被認為是古代ioi國的住民寫下的日記。joi教授為了通過這份日記來研究古代ioi國的生活,開始著手調查日記中記載的事件。日記中記錄了連續n天發生的時間,大約每天發生一件。事件有種類之分。第i天 1 i n 發生的事件的種類用乙個整數xi表示...