藉此學習回滾莫隊。
經典的莫隊:對於區間[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 就是過不了嗎!不爽,蒯個題解,再見...