BZOJ 4241 歷史研究

2021-08-08 06:20:21 字數 1969 閱讀 2915

藉此學習回滾莫隊。

經典的莫隊:對於區間[l

,r] 向別的區間轉移狀態時。有時是刪除。有時是插入。同時需要維護。這類問題需要插入和刪除,以及維護比較快的情況下。才可以實現。

回滾莫隊:插入和刪除是互反的操作。對於有些問題。插入和刪除好辦。維護困難。回滾莫隊可以解決:插入維護時困難,或者,刪除維護時困難的問題。(必須有乙個容易辦到)

這裡回滾模隊意思應該是保留了某個區間的狀態。

更直白的說。插入和刪除簡單。某個操作的維護不簡單。

對於那個操作。我們也不打算維護。而是記錄。

我們對序列按

m 分塊後。形成[k

m,km

+m]

的區間。我們記詢問

有:li

,ri,

為:li

∈[km

,km+

m],r

i>km

+m我們對區間分開維護:

對於插入簡單,且插入維護簡單的問題。

每次只維護[k

m+m+

1,ri

] 對於

[li,

km+m

] ,直接暴力插入。求解。然後刪除(不維護的刪除,將[l

i,km

+m] 產生的影響消去。這就需要我們記錄[k

m+m+

1,ri

] 的狀態了。)

相反。對於刪除簡單。可以倒著來。t(

n)=o

(nn‾

√)這個題目可以說上面思想的模版題了。

#include 

#include

#include

#include

#define maxn 100005

using

namespace

std;

typedef

long

long ll;

const

char l='0'-1;

const

char r='9'+1;

struct io

io()

int read()

while(*pb==' '||*pb=='\n'||*pb=='\r')

}int ans=0;

while(*pb>l&&*pb10+(*pb-'0');

pb++;

if(pb==pe)

}return ans;

}}i;struct node

bool

operator

<(const node &a)const

for(int i=0;iint size=(int)(unique(tmp,tmp+n)-tmp);

for(int i=1;i<=n;i++) x[i]=(int)(lower_bound(tmp,tmp+size,x[i])-tmp);

int v=0,l=-1,r=-1;

ll maxn=0;

for(int i=0;iif(l!=q[i].l)

while(rif(vis[x[r]]0;

vis[x[r]]=v;

cnt[x[r]]+=tmp[x[r]];

if(cnt[x[r]]>maxn)maxn=cnt[x[r]];

}ll bu=maxn;

int s=min(l,q[i].r+1);

for(int j=q[i].l;jif(vis[x[j]]0;

vis[x[j]]=v;

cnt[x[j]]+=tmp[x[j]];

if(cnt[x[j]]>bu)bu=cnt[x[j]];

}ans[q[i].id]=bu;

for(int j=q[i].l;jfor(int i=0;iprintf("%lld\n",ans[i]);

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 就是過不了嗎!不爽,蒯個題解,再見...