【模板】普通平衡树(Treap/SBT)
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
-
插入x数
-
删除x数(若有多个相同的数,因只删除一个)
-
查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
-
查询排名为x的数
-
求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
输入输出格式
输入格式:
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号( 1 \leq opt \leq 61≤opt≤6 )
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
#include <bits/stdc++.h> using namespace std; const int maxn = 100000+5; const int inf = 2000000008; int root,tot; struct Splay{ int ch[maxn][2],fa[maxn],siz[maxn],key[maxn], same[maxn]; void init(int t, int val = 0, int par = 0){ ch[t][0] = ch[t][1] = 0; key[t] = val;same[t] = 1; fa[t] = par; } void up(int t){ siz[t] = siz[ch[t][1]] + siz[ch[t][0]] + same[t]; } void init(){ init(0, 0, 0); tot = root = 0; } void rotate(int x, int d){ int y = fa[x]; ch[y][d^1] = ch[x][d]; if(ch[x][d])fa[ch[x][d]] = y; fa[x] = fa[y]; if(fa[y]){ if(y == ch[fa[y]][0])ch[fa[y]][0] = x; else ch[fa[y]][1] = x; } ch[x][d] = y;fa[y] = x; up(y); // father first up(x); } void splay(int x, int targrt){ while(fa[x] != targrt){ int y = fa[x]; if(x == ch[y][0]){ if(targrt != fa[y] && y == ch[fa[y]][0]) rotate(y, 1); rotate(x, 1); } else { if(targrt != fa[y]&& y == ch[fa[y]][1]) rotate(y, 0); rotate(x, 0); } } if(!targrt)root = x; } void insert( int x,int t = root, int par = 0){ if(!t){ t = ++tot; init(t, x, par); ch[par][x > key[par]] = t; splay(t, 0); } else{ if(x == key[t]){ same[t]++; up(t); //! } else if(x < key[t]){ insert(x, ch[t][0], t); up(t); } else { insert(x, ch[t][1], t); up(t); } } } int rank(int x,int t = root){ if(!t)return 0; if(x == key[t])return siz[ch[t][0]]+1; if(x < key[t])return rank(x, ch[t][0]); return siz[ch[t][0]]+same[t]+rank(x, ch[t][1]); } int query(int x, int t = root){ if(!x)return t; if(x > siz[ch[t][0]] + same[t]) return query(x - same[t] - siz[ch[t][0]], ch[t][1]); if(x <= siz[ch[t][0]])return query(x, ch[t][0]); return t; } void Query(int x){ printf("%d\n",key[query(x)]); } void erase(int x){ int t = root; while(key[t] != x)t = ch[t][x > key[t]]; splay(t, 0); if(same[t]>1){ same[t]--; up(t); //! return; } same[t] = 0; int y = ch[t][1]; bool b; if(!y)y = ch[root][0], b = 1; else b = 0; if(!y)root = 0,same[t] = 0;//有可能只有一个节点 while(ch[y][b])y = ch[y][b]; splay(y, root); ch[y][b] = ch[root][b]; if(ch[root][b]) fa[ch[root][b]] = y; fa[y] = 0; root = y; up(y); //! } int getpre(int x){ int ret = -inf, t = root; while(t){ if(key[t] < x)ret = max(ret, key[t]); t = ch[t][x > key[t]]; } return ret; } int getscc(int x){ int ret = inf, t = root; while(t){ if(key[t] > x) ret = min(ret, key[t]); t = ch[t][x >=key[t]]; } return ret; } void print(){ for(int i = 1; i <= tot; i++) printf("%d %d %d\n",i, ch[i][0], ch[i][1]); } }Tr; int main() { int n; scanf("%d",&n); Tr.init(); while(n--){ int opt,x; scanf("%d%d",&opt,&x); switch(opt){ case 1:Tr.insert(x);break; case 2:Tr.erase(x);break; case 3:printf("%d\n",Tr.rank(x));break; case 4:Tr.Query(x);break; case 5:printf("%d\n",Tr.getpre(x));break; case 6:printf("%d\n",Tr.getscc(x));break; } //Tr.print(); } return 0; }