\[ Preface \]c++
以前用 treap 打,交了四遍才過。spa
自學了 fhq treap 後,才意識到是一道 fhq treap 板子題,直接碼上,一遍就過。code
本題解提供的是 fhq treap 作法(感謝 fhq 神犇),不太瞭解 fhq treap 的同窗能夠去了解一下 fhq treap ,挺好理解的。(至少要了解兩種 split 和 merge 操做)
\[ Description \]
你須要維護一個可重集,支持 \(4\) 種操做:ip
I k
向集合內插入元素 \(k\) 。get
A k
將集合內全部元素加上 \(k\) 。it
S k
將集合內全部元素減去 \(k\) 。io
F k
查詢集合內第 \(k\) 大。class
一共 \(n\) 次操做。查詢
一開始給出一個下界 \(Minv\) ,表示集合內的全部元素必須大於等於 \(Minv\) ,在任什麼時候刻,小於 \(Minv\) 的全部元素會被馬上刪除。集合
最後還要輸出被刪除的元素個數。
\[ Solution \]
對於 I k
操做:
首先先判斷一下 \(k\) 是否大於等於 \(Minv\) ,以後就是經典的插入操做了。
讓原樹按 \(k-1\) 值分裂成兩棵樹 \(x,y\) ,新建值爲 \(k\) 的節點 \(New\) ,合併 \(x,New,y\) 。
\(~\)
對於 A k
和 S k
操做:
考慮到 " A
和 S
命令的總條數不超過 100 " ,想到了啥?暴力修改!
顯然集合內的全部元素加上 \(k\) 或減去 \(k\),fhq treap 樹形態不變。
A k
操做就很好辦了,集合內的全部元素加上 \(k\) 當然仍是大於等於 \(Minv\) ,直接 \(dfs\) 暴力修改便可。
S k
操做以後還會致使一些元素小於 \(Minv\) ,這些元素在還沒操做前是小於 \(Minv+k\) 的。
那麼咱們能夠將原樹按 \(Minv+k-1\) 值分裂成兩棵樹 \(x,y\) 。樹 \(x\) 的全部元素在操做以後都是小於 \(Minv\) 的,那麼這次被刪除的元素個數即爲 \(size[x]\) ,將其累加進答案,隨後樹 \(x\) 就沒有用了,不用管它就好了。樹 \(y\) 的全部元素在操做以後都是大於等於 \(Minv\) 的,直接 \(dfs\) 暴力修改,最後將樹 \(y\) 當成原樹就好了。
\(~\)
對於 F k
操做:
經典的查詢第 \(k\) 大。
讓原樹按 \(size[root]-k\) 大小分裂成兩棵樹 \(x,y\) ,再讓樹 \(y\) 按 \(1\) 大小分裂成兩棵樹 \(y,z\) ,此時樹 \(y\) 只有一個節點,這個節點就是咱們要找的第 \(k\) 大了,最後記得合併回去。
固然,在 " 按大小分裂 " 上作一點小改動,或是用通常 treap 的查詢第 k 大也是能夠的。
\(~\)
至此,此題獲得完美解決。
\[ Code \]
#include<cstdio> #include<cstdlib> #include<algorithm> #define RI register int using namespace std; inline int read() { int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } const int N=100100; int m,Minv; int tot,root; struct treap{ int lc,rc; int val,dat; int size; }t[N]; int New(int val) { tot++; t[tot].lc=t[tot].rc=0; t[tot].val=val; t[tot].dat=rand(); t[tot].size=1; return tot; } void upd(int p) { t[p].size=t[t[p].lc].size+t[t[p].rc].size+1; } void split_v(int p,int val,int &x,int &y) { if(!p) x=y=0; else { if(t[p].val<=val) x=p,split_v(t[p].rc,val,t[p].rc,y); else y=p,split_v(t[p].lc,val,x,t[p].lc); upd(p); } } void split_s(int p,int size,int &x,int &y) { if(!p) x=y=0; else { if(t[t[p].lc].size<size) x=p,split_s(t[p].rc,size-t[t[p].lc].size-1,t[p].rc,y); else y=p,split_s(t[p].lc,size,x,t[p].lc); upd(p); } } int merge(int p,int q) { if(!p||!q) return p^q; if(t[p].dat>t[q].dat) { t[p].rc=merge(t[p].rc,q),upd(p); return p; } else { t[q].lc=merge(p,t[q].lc),upd(q); return q; } } int x,y,z; void insert(int val) { split_v(root,val-1,x,y); root=New(val); root=merge(x,root); root=merge(root,y); } void dfs(int u,int val) { if(!u)return; t[u].val+=val; dfs(t[u].lc,val),dfs(t[u].rc,val); } int GetValByRank(int rank) { if(t[root].size<rank) return -1; split_s(root,t[root].size-rank,x,y); split_s(y,1,y,z); int ans=t[y].val; root=merge(x,y); root=merge(root,z); return ans; } int ans; int main() { m=read(),Minv=read(); while(m--) { char op[2];scanf("%s",op); int val=read(); switch(op[0]) { case 'I':{ if(Minv<=val) insert(val); break; } case 'A':{ dfs(root,val); break; } case 'S':{ split_v(root,Minv+val-1,x,root); ans+=t[x].size; dfs(root,-val); break; } case 'F':{ printf("%d\n",GetValByRank(val)); break; } } } printf("%d\n",ans); return 0; }
\[ Thanks \ for \ watching \]