Treap是真的简单。
为了打破类似单调数列插入BST,
使树退化为链表的情况,
将数据打乱成随机出现的,是个好办法,
然而并不是什么时候都适用。
树上节点的出现顺序是不可修改的,
而Treap则为每个节点新增加一个随机变量,
将矛盾转移到这个随机变量上,
使得对节点进行比较的时候,具有随机性,
从而使得插入,删除等操作的复杂度期望为O(logn)。
Treap性质:
1.左右子树的优先级小于父亲。
插入:
与BST同样的,左小右大跑子树,插入节点,没什么特殊的。
回溯时进行修正。
删除:
平衡二叉树删除节点总是这样:
1.找到待删除的节点。
2.如果它没有儿子,或是只有一个儿子,可以就地删除,后续接上。
3.如果它有两个儿子,则继续递归,找它的前驱,用前驱替换待删除节点,删除前驱节点。
回溯时进行修正。
修正:
插入时,引入新节点,需要修正。
删除时,从叶子替换了一个节点过来,需要修正。
步骤:
1.判断当前节点优先值小于父亲优先值,如果它是左儿子则右旋,否则左旋。
没了。
#include <iostream>
#include <cstdio>
#include <climits>
#include <cstdlib>
#include <fstream>
using namespace std;
struct Tree {
int num, num2, value, rand;
Tree *lChild, *rChild;
}*T, *NIL;
void lTurn(Tree *&th) {
Tree *p = th;
th = th->rChild;
p->rChild = th->lChild;
th->lChild = p;
}
void rTurn(Tree *&th) {
Tree *p = th;
th = th->lChild;
p->lChild = th->rChild;
th->rChild = p;
}
void updateNode(Tree *th) {
if (th != NIL) {
th->num2 = th->lChild->num2 + th->rChild->num2 + th->num;
}
}
void balance(Tree *th, Tree *&par) {
if (th != NIL && par != NIL) {
if (th->rand > par->rand) {
if (th == par->lChild) {
rTurn(par);
} else {
lTurn(par);
}
}
updateNode(par->lChild);
updateNode(par->rChild);
}
updateNode(par);
}
void insertNode(Tree *&th, int value, Tree *&par = NIL) {
if (th == NIL) {
th = new Tree;
th->num = th->num2 = 1;
th->value = value;
th->lChild = th->rChild = NIL;
th->rand = rand();
} else if (th->value == value) {
++th->num;
++th->num2;
} else {
insertNode(value < th->value? th->lChild: th->rChild, value, th);
}
balance(th, par);
}
void deleteNode(Tree *&th, int value, Tree *&par = NIL, Tree *q = NIL) {
if (q == NIL) {
if (th->value == value) {
if (th->num > 1) {
--th->num;
--th->num2;
} else if (th->lChild == NIL || th->rChild == NIL) {
Tree *p = th;
th = th->lChild != NIL? th->lChild: th->rChild;
delete p;
} else {
deleteNode(th->lChild, value, th, th);
}
} else {
deleteNode(value < th->value? th->lChild: th->rChild, value, th);
}
} else {
if (th == NIL) {
Tree *p = par;
q->num = par->num;
q->rand = par->rand;
q->value = par->value;
par = par->lChild;
delete p;
} else {
deleteNode(th->rChild, value, th, q);
}
}
balance(th, par);
}
int getRank(Tree *th, int value) {
if (th == NIL) {
return 0;
} else if (th->value < value){
return th->lChild->num2 + th->num + getRank(th->rChild, value);
} else {
return getRank(th->lChild, value);
}
}
int getSa(Tree *th, int sa) {
if (th == NIL) {
return -1;
} else {
int lower_sa = th->lChild->num2 + 1;
int upper_sa = lower_sa + th->num;
if (sa < lower_sa) {
return getSa(th->lChild, sa);
} else if (sa < upper_sa) {
return th->value;
} else {
return getSa(th->rChild, sa - upper_sa + 1);
}
}
}
int getPre(Tree *th, int value) {
if (th == NIL) {
return -1 << 30;
} else if (th->value < value) {
int x = getPre(th->rChild, value);
return (x != -1 << 30)? x: th->value;
} else {
return getPre(th->lChild, value);
}
}
int getSuf(Tree *th, int value) {
if (th == NIL) {
return 1 << 30;
} else if (th->value > value) {
int x = getSuf(th->lChild, value);
return (x != 1 << 30)? x: th->value;
} else {
return getSuf(th->rChild, value);
}
}
int main() {
srand(time(0));
NIL = new Tree;
NIL->num = NIL->num2 = 0;
NIL->rand = INT_MIN;
T = NIL;
int n, opt, x;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%d", &opt, &x);
switch(opt) {
case 1:insertNode(T, x);break;
case 2:deleteNode(T, x);break;
case 3:printf("%d\n", getRank(T, x) + 1);break;
case 4:printf("%d\n", getSa(T, x));break;
case 5:printf("%d\n", getPre(T, x));break;
case 6:printf("%d\n", getSuf(T, x));break;
}
}
return 0;
}