模板——Treap实现名次树
Treap 是一种通过赋予结点随机权值的一种满足堆性质的二叉搜索树,它很好的解决了二叉搜索树顺序插入组成链式的局限性。
名次树是指在treap的每个结点中添加附加域size,表示以它为根的子树的总结点树。
名次树支持两个操作:
Kth(x): 找出第k小(第k大)的元素。
Rank(x): 值x的名次,即比x小(大)的结点个数加 1 。
以第k大为例,代码如下:
1 struct Node { 2 Node *ch[2]; 3 int r; //随机权值 4 int v; //值 5 int s; //附加域size 6 Node(int vv): v(vv) { 7 s = 1; 8 ch[0] = ch[1] = NULL; 9 r = rand(); 10 } 11 int cmp(int x) const { 12 if(x == v) return -1; 13 return x < v ? 0 : 1; 14 } 15 void maintain() { 16 s = 1; 17 if(ch[0] != NULL) s += ch[0]->s; 18 if(ch[1] != NULL) s += ch[1]->s; 19 } 20 }; 21 22 void rotate(Node* &o, int d) { //旋转操作 23 Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o; 24 o->maintain(); k->maintain(); o = k; 25 } 26 27 void insert(Node* &o, int x) { //插入操作 28 if(o == NULL) o = new Node(x); 29 else { 30 int d = x < o->v ? 0 : 1; //注意相等时处理方式可以改变 31 insert(o->ch[d], x); 32 if(o->ch[d]->r > o->r) rotate(o, d^1); 33 } 34 o->maintain(); 35 } 36 void remove(Node* &o, int x) { //删除操作 37 int d = o->cmp(x); 38 Node* u = o; 39 if(d == -1) { 40 if(o->ch[0] != NULL && o->ch[1] != NULL){ 41 int d2 = o->ch[0]->r > o->ch[1]->r ? 1 : 0; 42 rotate(o, d2); 43 remove(o->ch[d2], x); 44 } 45 else { 46 if(o->ch[0] == NULL) o = o->ch[1]; else o = o->ch[0]; 47 delete u; 48 } 49 } 50 else remove(o->ch[d], x); 51 if(o != NULL) o->maintain(); 52 } 53 54 int kth(Node* o, int k) { //找第k大 55 if(o == NULL || k > o->s || k <= 0) return 0; 56 int s = o->ch[1] == NULL ? 0 : o->ch[1]->s; 57 if(k == s+1) return o->v; 58 else if(k <= s) return kth(o->ch[1], k); 59 else return kth(o->ch[0], k-s-1); 60 }