所谓Treap,就是一种二叉查找树,而我们知道二叉查找树,相对来说比较容易形成最坏的链表情况,所以我们有一种数据结构来防止二叉查找树出现最坏情况,那就是Treap。
Treap=tree+heap,Treap就是这样一种既是树又是堆的奇怪的东东。我们每次插入节点时,便随机的给每个节点赋给一个值,我们要求原始数据满足二叉查找树的性质,而随机值要满足堆的性质。
比如下面的一棵树:
首先我们知道各个节点的“优先级”是采用随机数的方法,那么就存在一个问题,当我们插入一个节点后,优先级不满足“堆定义"的。那么我们就要旋转这课树。
①: 左左情况旋转
②: 右右情况旋转
好在我们写一个旋转函数就可以同时维护左旋和右旋了:
void play(Treap* &rr,int d){
Treap *k=rr->ro[d^];
rr->ro[d^]=k->ro[d];//ro[0]是左孩子,ro[1]是右孩子
k->ro[d]=rr;
rr->rub();//rub()函数的作用是重新统计该子树的大小
k->rub();//必须先rr再k,因为现在rr是k的孩子
rr=k;
}
那么我们就可以刷水题了:(洛谷-普通平衡树)
#include<bits/stdc++.h>
#define sight(c) ('0'<=c&&c<='9')
#define RR NULL
#define inf 1<<29
#define random rrsbRRsb
using namespace std;
inline int random(){
static int seed=;
return seed=int(seed*48271LL%);
}
struct Treap{
int key,rap,siz;
Treap *ro[];
Treap(int k){
siz=;
key=k;
rap=random();
ro[]=ro[]=RR;
}
inline void rub() {
siz=;
if (ro[]!=RR) siz+=ro[]->siz;
if (ro[]!=RR) siz+=ro[]->siz;
}
inline int cop(int x){
if (x==key) return -;
return x<key?:;
}
};
inline void read(int &x) {
static char c; static int b;
for (b=,c=getchar();!sight(c);c=getchar()) if (c=='-') b=-;
for (x=;sight(c);c=getchar()) x=x*+c-;
x*=b;
}
void play(Treap* &rr,int d){
Treap *k=rr->ro[d^];
rr->ro[d^]=k->ro[d];
k->ro[d]=rr;
rr->rub();
k->rub();
rr=k;
}
void Insert(Treap* &rr,int x){
if (rr==RR) rr=new Treap(x);
else {
int d=x < rr->key?:;
Insert(rr->ro[d],x);
if (rr->ro[d]->rap > rr->rap)
play(rr,d^);
}
rr->rub();
}
bool Find(Treap *p,int x){
while(p!=RR) {
int d=p->cop(x);
if (d==-) return true;
p=p->ro[d];
}
return false;
}
void Delete(Treap* &t,int x){
int d=t->cop(x);
if (d==-) {
Treap *tmp=t;
if (t->ro[]==RR) {
t=t->ro[];
delete tmp;
tmp=RR;
} else if (t->ro[]==RR) {
t=t->ro[];
delete tmp;
tmp=RR;
} else {
int k=t->ro[]->rap<t->ro[]->rap?:;
play(t,k);
Delete(t->ro[k],x);
}
}
else Delete(t->ro[d],x);
if (t!=RR) t->rub();
}
int Kth(Treap *t,int k){
int cm=;
if (t->ro[]) cm=t->ro[]->siz;
cm++;
if (cm==k)
return t->key;
if (cm>k) return Kth(t->ro[],k);
return Kth(t->ro[],k-cm);
}
int Rank(Treap *t,int k){
int r;
if (!t) return inf;
if (t->ro[]==RR)
r=;else r=t->ro[]->siz;
if(k==t->key) return min(r+,Rank(t->ro[],k));
if(k<t->key)
return Rank(t->ro[],k);
return r++Rank(t->ro[],k);
}
int Pre(Treap *t,int k){
if (!t) return -inf;
if (k>t->key) return max(t->key,Pre(t->ro[],k));
return Pre(t->ro[],k);
}
int Sub(Treap *t,int k){
if (!t) return inf;
if (k<t->key) return min(t->key,Sub(t->ro[],k));
return Sub(t->ro[],k);
}
int n,op,x;
int main () {
freopen("a.in","r",stdin);
read(n);
Treap* root=RR;
while (n--) {
read(op); read(x);
switch(op){
case :Insert(root,x);break;
case :Delete(root,x);break;
case :printf("%d\n",Rank(root,x));break;
case :printf("%d\n",Kth(root,x));break;
case :printf("%d\n",Pre(root,x));break;
case :printf("%d\n",Sub(root,x));break;
}
// cout<<op<<endl;
}
return ;
}