\[ 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 \]