Treap是一种BST,可以山寨set,另外还可以实现set实现不了的“名次树”。它可以说是一个满足堆性质的BST。“堆性质”是为了维护它的平衡,对于每个节点,都给它随机一个值,作为堆性质的关键字。所以,Treap的使用要看一点点人品,随机出的优先值在大多数情况下还是可以使BST趋于平衡的,各个操作的期望复杂度是O(logn)。
写一个能实现名次树的Treap需要多开一个size数组,支持以下操作:
1.插入新节点
2.删除某节点
3.查询键值为x的节点
4.查询名次为x的节点
5.查询键值为x的节点的名次
对于插入,先随机一个用于比较优先级的键值,然后按照普通BST的方式插入,插入完成后根据键值进行旋转,直至优先级满足堆性质。
对于删除,如果待删除节点只有一棵子树,直接把它的子节点连接到它的父节点即可,否则就在满足堆性质的前提下旋转(左子树优先级大于右子树,那么把左子树旋转到根),待删除节点深度变大,总会在某次旋转后变成叶子节点,这时也可以直接删除。
对于查询,查询键值就如同普通的BST。查询第k小的从根节点开始递归,如果左子树大小大于k+1,进入左子树,否则进入右子树,并且k -= 左子树大小+1,直到k等于当前结点左子树大小+1为止。查询键值为x的节点名次就是它的左子树大小+1。
Treap理解起来很容易,代码相比其他BST也算好写,就作为自己第一个学习的BST了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Node
{
int lc, rc, fa, size, d, k;
Node() {lc = rc = size = 0;}
void init(int _fa, int _k)
{
fa = _fa, k = _k, d = rand(), size = 1;
}
};
struct Treap
{
#define M 1111
Node T[M]; int num, root;
Treap () {memset(T, 0, sizeof T); num = root = 0;}
void Rota_L(int rt) // lc be the root
{
T[0].size = 0;
int Fa = T[rt].fa, Lc = T[rt].lc, Rc = T[Lc].rc;
if(rt == root) root = Lc, T[Lc].fa = 0;
else
{
T[Lc].fa = Fa;
if(T[Fa].lc == rt) T[Fa].lc = Lc;
if(T[Fa].rc == rt) T[Fa].rc = Lc;
}
T[Rc].fa = rt, T[rt].fa = Lc;
T[rt].lc = Rc, T[Lc].rc = rt;
int t = T[rt].size;
T[rt].size -= (T[Lc].size - T[Rc].size);
T[Lc].size = t;
}
void Rota_R(int rt) // rc be the root
{
T[0].size = 0;
int Fa = T[rt].fa, Rc = T[rt].rc, Lc = T[Rc].lc;
if(rt == root) root = Rc, T[Rc].fa = 0;
else
{
T[Rc].fa = Fa;
if(T[Fa].lc == rt) T[Fa].lc = Rc;
if(T[Fa].rc == rt) T[Fa].rc = Rc;
}
T[Lc].fa = rt, T[rt].fa = Rc;
T[rt].rc = Lc, T[Rc].lc = rt;
int t = T[rt].size;
T[rt].size -= (T[Rc].size - T[Lc].size);
T[Rc].size = t;
}
void change(int rt, int k)
{
if(!rt) return ;
T[rt].size+=k; change(T[rt].fa, k);
}
void Maintain(int rt)
{
Node Rt = T[rt], Fa = T[T[rt].fa];
if(Rt.d < Fa.d || !Rt.fa) return ;
if(Fa.lc == rt) Rota_L(Rt.fa);
if(Fa.rc == rt) Rota_R(Rt.fa);
Maintain(rt);
}
bool insert(int rt, int k)
{
if(!rt) {root = ++num; T[num].init(0, k); return 1;}
if(T[rt].k == k) return 0;
if(T[rt].k < k)
{
if(T[rt].rc) return insert(T[rt].rc, k);
T[rt].rc = ++num; change(rt, 1);
T[num].init(rt, k);
Maintain(num);
return 1;
}
if(T[rt].k > k)
{
if(T[rt].lc) return insert(T[rt].lc, k);
T[rt].lc = ++num; change(rt, 1);
T[num].init(rt, k);
Maintain(num);
return 1;
}
}
bool insert(int k) {return insert(root, k); }
int rank(int rt, int k)
{
if(!rt) return 0;
T[0].size = 0;
int Lc = T[rt].lc, Rc = T[rt].rc;
if(k == T[rt].k) return T[Lc].size+1;
if(k < T[rt].k) return rank(Lc, k);
if(k > T[rt].k) return rank(Rc, k) + T[Lc].size + 1;
}
int rank(int k) {return rank(root, k);}
int find(int rt, int k)
{
if(!rt) return 0; T[0].size = 0;
int Lc = T[rt].lc, Rc = T[rt].rc;
if(k == T[Lc].size+1) return rt;
if(k < T[Lc].size+1) return find(Lc, k);
if(k > T[Lc].size+1) return find(Rc, k-T[Lc].size-1);
}
int find(int k) {return find(root, k);}
void dele(int rt)
{
int Fa = T[rt].fa, Lc = T[rt].lc, Rc = T[rt].rc;
if(!Lc || !Rc)
{
int nxt = Lc ? Lc: Rc;
if(root == rt) { root = nxt; return ;}
if(T[Fa].lc == rt) T[Fa].lc = nxt;
if(T[Fa].rc == rt) T[Fa].rc = nxt;
change(Fa, -1); T[nxt].fa = Fa;
return ;
}
if(T[Lc].d > T[Rc].d) Rota_L(rt); else Rota_R(rt);
dele(rt);
}
bool del(int rt, int k)
{
if(!rt) return 0;
if(T[rt].k == k) {dele(rt); return 1;}
if(T[rt].k < k) return del(T[rt].rc, k);
if(T[rt].k > k) return del(T[rt].lc, k);
}
bool del(int k) {return del(root, k);}
void print(int rt)
{
if(!rt) return ;
print(T[rt].lc);
printf("%d ", T[rt].k);
print(T[rt].rc);
}
void print() {print(root); putchar('\n');}
};
int main()
{
srand(time(NULL));
Treap test;
int n, q; scanf("%d", &q);
while(q--)
{
int x, c; scanf("%d %d", &x, &c);
if(x == 1) test.insert(c);
if(x == 2) test.del(c);
if(x == 3) printf("%d\n", test.rank(c));
if(x == 4) printf("%d\n", test.T[test.find(c)].k);
test.print();
}
return 0;
}