練習 BZOJ4241 歷史研究(回滾莫隊)

2021-08-21 23:47:37 字數 2048 閱讀 9231

給定乙個長度為

n n

的序列,並提出

q' role="presentation">q

q個詢問,每次詢問要求回答區間 [l

,r] [l,

r]

內所有的權值與其出現次數的積的最大值。

我一看,區間問題,無修改可以離線,上莫隊妥妥的,但是仔細一想,當區間擴充時,可以o(

1)o (1

)的求出新區間答案,但是當區間縮小時,就不能o(

1)o (1

)做到了,莫隊演算法的複雜度不能得到保證。

這時候就可以考慮回滾莫隊,其思想還是對詢問排序,並且對區間的雙指標有優化。

普通的莫隊演算法,初始的l,

r l,r

就是第乙個詢問的位置的[l

,r] [l,

r]

,之後對l,

r l,r

就沒有人為的修改操作,只讓他隨著詢問變化,在能夠o(

1)o (1

)求出新區間答案的時候,這樣的莫隊演算法保證了複雜度在

n1.5

n

1.5。

此時,由於不能直接o(

1)o (1

)求出區間擴張(或收縮)的時候,需要手動調整這兩個指標的位置,以達到回滾的操作。

第一步,對序列分塊,詢問排序。

第二步,指定ql為當前詢問的l所在塊的下一塊的第乙個元素,指定qr為當前詢問l所在塊的最後乙個元素。對於每乙個詢問,我們要判斷

如果當前詢問的r也在l的塊內,那麼直接暴力統計區間答案,複雜度不超過n−−√n

。如果當前詢問的r不在l的塊內,那麼就讓qr向右拓展,並暫存拓展結果,讓ql向左拓展,然後統計區間

答案。這一步和普通的莫隊沒有區別。

第三步,回滾。我們讓ql回滾到當前l所在塊的下一塊第乙個元素,為下一次詢問做準備。恢復暫存的拓展結果

對於以上步驟,如果詢問l所在塊與上乙個詢問l所在塊不同,就需要重新指定ql和pr。

由於在乙個塊內的詢問,qr是不回退的,這就保證了複雜度!

如果還是不明白,可以看看下面的部落格。

#include

using

namespace

std;

typedef

double db;

typedef

long

long ll;

typedef

unsigned

long

long ull;

const

int nmax = 1e5+7;

const

int inf = 0x3f3f3f3f;

const ll linf = 0x3f3f3f3f3f3f3f3f;

const ull p = 67;

const ull mod = 1610612741;

int n,m;

vector

v;ll t;

ll a[nmax],inocc[nmax],glocc[nmax],ans;

int belong[nmax],idx[nmax],sz,r[nmax];

struct nodeq[nmax];

int getid(ll x)

bool cmp(node a, node b)

inline

void modify(int pos,ll val)

inline

void del(int pos)

int main()

if(belong[q[i].l] == belong[q[i].r])

q[i].ans = temp;

}else

}sort(q+1,q+1+m,cmpid);

for(int i = 1;i<=m;++i) printf("%lld\n",q[i].ans);

return

0;}

bzoj4241 歷史研究

這題也是坑了好久 之前whx帶我刷joi的時候本來應該要做的。可是太懶沒有寫。區間詢問加權眾數。分塊,預處理出塊和塊之間的答案,記錄到第i個塊數字x出現了多少次。然後查詢的時候和普通眾數基本一樣,就是乘了個權值而已。要離散化。時間複雜度o nlogn mn 昨晚寫的常數太爛了。用了struct,陣列...

BZOJ4241 歷史研究

一眼覺得是莫隊,發現刪除不是很好搞,於是上回滾莫隊直接搞過 回滾莫隊用於處理難以刪除但是易於新增 其實易於刪除難以新增也可以,但是沒見過這樣題 的莫隊,排序照常,如果左右端點在同一塊直接暴力,這部分最多n sqrt n,否則把左端點在一塊的一起處理,清空莫隊,然後直接令莫隊左端點在塊尾,這部分n s...

bzoj4241 歷史研究

題目鏈結 看到題目就聯想到了 bzoj2809 apio2012 dispatching。想了想權值分塊 莫隊,發現不好維護塊內最值,又看了看80s的時間,於是怒水一發線段樹 莫隊,結果先wa後tle,不斷tle,無論怎麼改常數都不行,難道nlogn sqrt n 就是過不了嗎!不爽,蒯個題解,再見...