啊啊啊啊,终于学会打treap了啊啊啊啊啊
一个小故事
从前,Tree和Heap相遇了,他们相爱了,于是生下了一个孩子,他叫什么呢?于是他姓Tr名字叫eap,所以他就叫Treap(啦啦啦啦啦啦啦)
Treap的性质
既然他爸是Tree,他妈是Heap,那必定会遗传他爸和他妈的血统啊。
所以他是棵Balanced Binary Tree,同时从其每个点的键值来看,他的形态又是一棵不严格的Heap,当然由于这是从他妈那遗传的,所以他仅仅满足了Heap中:一个点的键值小于(或大于)他的两个儿子的键值。
插入
对于一个点的插入,我们像普通的二叉搜索树一样找到相应位置然后插入,注意我们要维护其heap的形态,所以我们要将新插入的点到根节点的路径类似普通的Heap的方法一样向上,但是由于这是棵二叉搜索树,于是我们要用旋转而非交换。
删除
删除一个节点,若其只有一个儿子或没有儿子,那么其直接用其儿子代替它或直接删掉,若它有两个儿子,那么看它的左右儿子那个键值小,若左儿子小则右旋,右儿子小则左旋,然后继续删除。
其它操作
由于其它操作与普通平衡树基本一样,我就不说了哈。
code(向hzw学习了呀)
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
typedef double db;
int get(){
char ch;
int s=0;
bool pd=0;
while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');
if (ch=='-')pd=1;
else s=ch-'0';
while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
if (pd)return -s;
return s;
}
const int N = 100010;
struct point{
int l,r,tot,v,key,w;
}tree[N];
int tot,n,root;
void updata(int x){
tree[x].tot=tree[tree[x].l].tot+tree[tree[x].r].tot+tree[x].w;
}
void rturn(int &x){
int y=tree[x].l;tree[x].l=tree[y].r;tree[y].r=x;
tree[y].tot=tree[x].tot;updata(x);x=y;
}
void lturn(int &x){
int y=tree[x].r;tree[x].r=tree[y].l;tree[y].l=x;
tree[y].tot=tree[x].tot;updata(x);x=y;
}
void insert(int &now,int x){
if (!now){
tree[now=++tot].v=x;
tree[now].key=rand();
tree[now].tot=tree[now].w=1;
return;
}
tree[now].tot++;
if (x==tree[now].v)tree[now].w++;
else
if (x<tree[now].v){
insert(tree[now].l,x);
if (tree[tree[now].l].key<tree[now].key)rturn(now);
}
else{
insert(tree[now].r,x);
if (tree[tree[now].r].key<tree[now].key)lturn(now);
}
}
void del(int &now,int x){
if (tree[now].v==x){
if (tree[now].w>1){
tree[now].w--;
tree[now].tot--;
return;
}
if (tree[now].l*tree[now].r==0)now=tree[now].l+tree[now].r;
else{
if (tree[tree[now].l].key<tree[tree[now].r].key)rturn(now),del(now,x);
else lturn(now),del(now,x);
}
return;
}
tree[now].tot--;
if (tree[now].v>x)del(tree[now].l,x);
else del(tree[now].r,x);
}
int rank(int now,int x){
if (!now)return -N;
if (tree[now].v==x)return tree[tree[now].l].tot+1;
if (x<tree[now].v)return rank(tree[now].l,x);
return tree[tree[now].l].tot+tree[now].w+rank(tree[now].r,x);
}
int kth(int now,int k){
if (!now)return 0;
if (tree[tree[now].l].tot<k&&k<=tree[tree[now].l].tot+tree[now].w)
return now;
if (k<=tree[tree[now].l].tot)return kth(tree[now].l,k);
return kth(tree[now].r,k-tree[tree[now].l].tot-tree[now].w);
}
int pre(int now,int x){
if (!now)return 0;
if (tree[now].v<x){
int v=pre(tree[now].r,x);
if (v)return v;
return now;
}
return pre(tree[now].l,x);
}
int suf(int now,int x){
if (!now)return 0;
if (tree[now].v>x){
int v=suf(tree[now].l,x);
if (v)return v;
return now;
}
return suf(tree[now].r,x);
}
int main(){
n=get();
srand(57789);
int tim=0;
fo(i,1,n){
int w,opt=get(),x=get();
switch(opt){
case 1:insert(root,x);break;
case 2:del(root,x);break;
case 3:printf("%d\n",rank(root,x));break;
case 4:w=kth(root,x);printf("%d\n",tree[w].v);break;
case 5:w=pre(root,x);printf("%d\n",tree[w].v);break;
case 6:w=suf(root,x);printf("%d\n",tree[w].v);break;
}
}
return 0;
}
建议学习新的平衡树可以用【bzoj3224】Tyvj 1728 普通平衡树 这题啊