【LOJ107】維護全序集
阿新 • • 發佈:2018-12-13
題目描述
這是一道模板題,其資料比「普通平衡樹」更強。
如未特別說明,以下所有資料均為整數。
維護一個多重集 S S S ,初始為空,有以下幾種操作:
- 把 x x x 加入 S S S
- 刪除 S S S 中的一個 x x x,保證刪除的 x x x 一定存在
- 求 S S S 中第 k k k 小
- 求 S S S 中有多少個元素小於 x x x
- 求 S S S 中小於 x x x 的最大數
- 求 S S S 中大於 x x x 的最小數
操作共 n n n 次。
輸入格式
第一行一個整數 n n n,表示共有 n n n 次操作 。
接下來 n n n 行,每行為以下幾種格式之一 :
0 x
,把 x x x 加入 S S S1 x
,刪除 S S S 中的一個 x x x,保證刪除的數在 S S S 中一定存在2 k
,求 S S S 中第 k k k 小的數,保證要求的數在 S S S 中一定存在3 x
,求 S S S 中有多少個數小於 x x x4 x
,求 S S S 中小於 x x x 的最大數,如果不存在,輸出 −1 -1 −15 x
,求 S S S 中大於 x x x 的最小數,如果不存在,輸出 −1 -1 −1
輸出格式
對於每次詢問,輸出單獨一行表示答案。
樣例
樣例輸入
5
0 3
0 4
2 2
1 4
3 3
樣例輸出
4
0
資料範圍與提示
1≤n≤3×105,0≤x≤109 1 \leq n \leq 3 \times 10 ^ 5, 0 \leq x \leq 10 ^ 9 1≤n≤3×105,0≤x≤109
程式碼(旋轉Treap):
#include <bits/stdc++.h> using namespace std; const int inf=1e9+7; const int Max=300005; int n,m,tot,root=1,ans; struct shu{int l,r,data,num,size,cnt;}; shu a[Max]; inline int get_int() { int x=0,f=1; char c; for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar()); if(c=='-') f=-1,c=getchar(); for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0'; return x*f; } inline void print(int x) { if(x<0) x=-x,putchar('-'); if(x>9) print(x/10); putchar('0'+x%10); } inline int NEW(int x) { a[++tot].num=x; a[tot].size=a[tot].cnt=1; a[tot].data=rand(); return tot; } inline void update(int p) { a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt; } inline void build() { NEW(-inf),NEW(inf); a[1].r=2; update(root); } inline void zig(int &p) { int q=a[p].l; a[p].l=a[q].r,a[q].r=p,p=q; update(a[p].r),update(p); } inline void zag(int &p) { int q=a[p].r; a[p].r=a[q].l,a[q].l=p,p=q; update(a[p].l),update(p); } inline void Insert(int &p,int x) { if(!p){p=NEW(x);return;} if(a[p].num==x){a[p].cnt++,update(p);return;} if(x<a[p].num) { Insert(a[p].l,x); if(a[a[p].l].data>a[p].data) zig(p); } else { Insert(a[p].r,x); if(a[a[p].r].data>a[p].data) zag(p); } update(p); } inline void Remove(int &p,int x) { if(a[p].num==x) { if(a[p].cnt>1) {a[p].cnt--,update(p);return;} if(a[p].l||a[p].r) { if(!a[p].r||a[a[p].l].data>a[a[p].r].data) zig(p),Remove(a[p].r,x); else zag(p),Remove(a[p].l,x); update(p); } else p=0; return; } if(x<a[p].num) Remove(a[p].l,x); else Remove(a[p].r,x); update(p); } inline int val(int p,int x) { if(!p) return 0; if(a[a[p].l].size>=x) return val(a[p].l,x); if(a[a[p].l].size+a[p].cnt>=x) return a[p].num; return val(a[p].r,x-a[a[p].l].size-a[p].cnt); } inline int sum(int p,int x) { if(!p) return 0; if(a[p].num==x) return a[a[p].l].size; if(x<a[p].num) return sum(a[p].l,x); return a[a[p].l].size+a[p].cnt+sum(a[p].r,x); } inline int pre(int p,int x) { if(!p) return -inf; if(x>a[p].num) return max(pre(a[p].r,x),a[p].num); return pre(a[p].l,x); } inline int nxt(int p,int x) { if(!p) return inf; if(x<a[p].num) return min(nxt(a[p].l,x),a[p].num); return nxt(a[p].r,x); } int main() { n=get_int();build(); for(int i=1;i<=n;i++) { int tag=get_int(),x=get_int(); switch(tag) { case 0: Insert(root,x); break; case 1: Remove(root,x); break; case 2: print(val(root,x+1)),putchar('\n'); break; case 3: print(sum(root,x)-1),putchar('\n'); break; case 4: ans=pre(root,x),print(ans==-inf?-1:ans),putchar('\n'); break; case 5: ans=nxt(root,x),print(ans==inf?-1:ans),putchar('\n'); break; } } return 0; }