一般平衡二叉树就是根据二叉log时间复杂度插入搜索之类的,如果插入的数小比如十万左右,那么好像可以权值线段树就行,但是如果是int范围那么只能二叉树了,所以这应该就是平衡二叉树的一个重要用法。
Treap树就是平衡二叉树,每个点都有两个值,分别是优先级和键值,Treap树满足父节点的优先级大于两个子节点(如果有的话),而且满足父节点的左子节点的键值小于父节点,右子节点键值大于父节点,所以如果每个节点的优先级已经确定好了的话的话,那么这个Treap树的形态也是确定好的,而优先级这东西是靠随机函数赋值的,所以最坏情况下可能会导致Treap树成为一条链,但是在数学期望下Treap基本是平衡的,所以要相信自己的人品。
这个是书上的版本,挺简单的,但是功能不全
struct node{
int size,rank,key;
node *son[2];
bool operator<(const node &a)const{return rank<a.rank;}
int cmp(int x)const{
if(x==key)
return -1;
return x<key?0:1;
}
void update(){
size=1;
if(son[0]!=NULL)
size+=son[0]->size;
if(son[1]!=NULL)
size+=son[1]->size;
}
};
void rotate(node* &o,int d){//d=0左旋 d=1右旋
node *k=o->son[d^1];
o->son[d^1]=k->son[d];
k->son[d]=o;
o->update();
k->update();
o=k;
}
void insert(node* &o,int x){//插入一个键值,随机赋优先级
if(o==NULL){
o=new node();
o->son[0]=o->son[1]=NULL;
o->rank=rand();
o->key=x;
o->size=1;
}
else{
int d=o->cmp(x);
insert(o->son[d],x);
o->update();
if(o<o->son[d])
rotate(o,d^1);
}
}
int kth(node* o,int k){//查找第k大
if(o==NULL||k<=0||k>o->size)
return -1;
int s=o->son[1]==NULL?0:o->son[1];
if(k==s+1)
return o->key;
else if(k<=s)
return kth(o->son[1],k);
else
return kth(o->son[0],k-s-1);
}
int find(node* o,int k){//找k这个数是第几大
if(o==NULL)
return -1;
int d=o->cmp(k);
if(d==-1){
/*if(o->son[1]==NULL)
return 1;
if(o->son[1]->cmp(k)==-1)
return find(o->son[1],k);
else
return o->son[1]->size+1;*/
//这个是如果k这个数有多个,找最小的那一个,比如12333,查3就是3
return o->son[1]==NULL?1:o->son[1]->size+1;
//这个是随便返回k这个数是第几大,比如12333,可能会是3,是4,是5
}
else if(d==0){
int tmp=find(o->son[0],k);
if(tmp==-1)
return -1;
else
return o->son[1]==NULL?tmp+1:tmp+1+o->son[1]->size;
}
else{
return find(o->son[d],k);
}
}
P3369 【模板】普通平衡树
1.插入x数
2.删除x数(若有多个相同的数,因只删除一个)
3.查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
4.查询排名为x的数
5.求x的前驱(前驱定义为小于x,且最大的数)
6.求x的后继(后继定义为大于x,且最小的数)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=101000;
const int INF=0x3f3f3f3f;
struct node{
int rank,key,w,size;
int son[2];
node(int key=0):key(key){
rank=rand()%100000;
son[0]=son[1]=0;
w=size=1;
}
}tree[MAX_N];
int root,cnt=0;
void update(int k){
tree[k].size=tree[tree[k].son[0]].size+tree[tree[k].son[1]].size+tree[k].w;
}
void rotate(int &k,int d){//d=0右旋
int t=tree[k].son[d];
tree[k].son[d]=tree[t].son[d^1];
tree[t].son[d^1]=k;
tree[t].size=tree[k].size;
update(k);
k=t;
}
void insert(int &k,int x){
if(k==0){
k=++cnt;
tree[k].key=x;
return;
}
if(tree[k].key==x){
tree[k].w++;
update(k);
return;
}
/*int d=x>tree[k].key;
int &t=tree[k].son[d];
if(tree[t].rank<tree[k].rank)
rotate(k,d);*/
if(x<tree[k].key){
int &t=tree[k].son[0];
insert(t,x);
if(tree[t].rank<tree[k].rank)
rotate(k,0);
}
else{
int &t=tree[k].son[1];
insert(t,x);
if(tree[t].rank<tree[k].rank)
rotate(k,1);
}
tree[k].size++;
}
int remove(int &k,int x){
if(k==0)
return 0;
if(x==tree[k].key){
if(tree[k].w>1){
tree[k].size--;
tree[k].w--;
return 1;
}
else{
if(tree[k].son[0]==0){
k=tree[k].son[1];
return 1;
}
if(tree[k].son[1]==0){
k=tree[k].son[0];
return 1;
}
if(tree[k].son[0]&&tree[k].son[1]){
if(tree[tree[k].son[0]].rank<tree[tree[k].son[1]].rank){
rotate(k,0);
tree[k].size--;
return remove(tree[k].son[1],x);
}
else{
rotate(k,1);
tree[k].size--;
return remove(tree[k].son[0],x);
}
}
}
}
if(!remove(tree[k].son[x<tree[k].key?0:1],x))
return 0;
tree[k].size--;
return 1;
}
int rank(int &k,int x){
if(!k)
return 0;
int left_size=tree[tree[k].son[0]].size;
if(x==tree[k].key)
return left_size+1;
if(x<tree[k].key)
return rank(tree[k].son[0],x);
else
return rank(tree[k].son[1],x)+tree[k].w+left_size;
}
int kth(int &k,int x){
if(!k)
return 0;
int left_size=tree[tree[k].son[0]].size;
//cout<<tree[k].son[0]<<"!\n";
if(left_size<x&&x<=left_size+tree[k].w)
return tree[k].key;
if(x<=left_size)
return kth(tree[k].son[0],x);
if(x>left_size+tree[k].w)
return kth(tree[k].son[1],x-left_size-tree[k].w);
}
int pred(int &k,int x){
if(!k)
return -INF;
if(x<=tree[k].key)
return pred(tree[k].son[0],x);
int res;
res=pred(tree[k].son[1],x);
return tree[k].key>res?tree[k].key:res;
}
int succ(int &k,int x){
if(!k)
return INF;
//cout<<tree[k].son[1]<<"!\n";
if(x>=tree[k].key)
return succ(tree[k].son[1],x);
int res;
res=succ(tree[k].son[0],x);
return tree[k].key<res?tree[k].key:res;
}
int main(void){
int n,i,op,x;
scanf("%d",&n);
root=0;
cnt=0;
tree[0].key=0;
tree[0].rank=0;
tree[0].w=0;
tree[0].size=0;
for(i=1;i<=n;i++){
//cout<<"root="<<root<<"\n";
scanf("%d%d",&op,&x);
if(op==1)
insert(root,x);
else if(op==2)
remove(root,x);
else if(op==3)
printf("%d\n",rank(root,x));
else if(op==4)
printf("%d\n",kth(root,x));
else if(op==5)
printf("%d\n",pred(root,x));
else if(op==6)
printf("%d\n",succ(root,x));
}
return 0;
}
Splay树可以把某个节点向上旋转到指定位置,特别是可以旋转到根的位置,所以形态不是固定的,而且分裂和合并非常方便。
P3369 【模板】普通平衡树
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX_N=101000;
int root,cnt;
int be[MAX_N];
int pre[MAX_N],size[MAX_N],son[MAX_N][2],w[MAX_N];
void update(int k){
size[k]=size[son[k][0]]+size[son[k][1]]+w[k];
}
int get(int k){
return son[pre[k]][1]==k;
}
void rotate(int x,int &t){
int y=pre[x],z=pre[y],d=get(x),d1=get(y);
if(y==t)
t=x;
else
son[z][d1]=x;
son[y][d]=son[x][d^1];
pre[son[x][d^1]]=y;
son[x][d^1]=y;
pre[y]=x;
pre[x]=z;
update(y);
update(x);
}
void splay(int x,int &t){
for(int y=pre[x],z=pre[y];x!=t;rotate(x,t),y=pre[x],z=pre[y])
if(y!=t)
rotate(get(x)==get(y)?y:x,t);
}
int search(int k){
int p=root;
while(p&&k!=be[p])
p=son[p][be[p]<k];
return p;
}
int pred(int k){
int t=son[k][0];
splay(k,root);
while(t&&son[t][1])
t=son[t][1];
return t;
}
int succ(int k){
int t=son[k][1];
splay(k,root);
while(t&&son[t][0])
t=son[t][0];
return t;
}
void remove(int k){
if(!k)
return;
splay(k,root);
if(w[k]>1){
w[k]--;
size[k]--;
return;
}
int l=son[k][0],r=son[k][1],now;
now=l;
pre[l]=pre[r]=son[k][0]=son[k][1]=0;
root=l;
while(now&&son[now][1])
now=son[now][1];
if(!now){
root=r;
return;
}
splay(now,root);
son[now][1]=r;
if(r)
pre[r]=now;
update(root);
}
int grank(int k){
splay(k,root);
return size[son[k][0]]+1;
}
int kth(int o,int k){
int left_size=size[son[o][0]];
if(k<=left_size+w[o]&&k>=left_size+1)
return o;
if(left_size>k-w[o])
return kth(son[o][0],k);
return kth(son[o][1],k-left_size-w[o]);
}
void insert(int k){
if(!root){
//cout<<"a1\n";
root=++cnt;
be[root]=k;
size[root]=w[root]=1;
son[root][0]=son[root][1]=pre[root]=0;
}
else if(search(k)){
//cout<<"a2\n";
int t=search(k);
splay(t,root);
size[t]++;
w[t]++;
}
else{
//cout<<"a3\n";
int x=root,y;
while(1){
y=son[x][be[x]<k];
if(!y){
y=++cnt;
be[y]=k;
size[y]=w[y]=1;
son[x][be[x]<k]=y;
son[y][0]=son[y][1]=0;
pre[y]=x;
break;
}
x=y;
}
splay(y,root);
}
}
int main(void){
int m,i,op,x;
scanf("%d",&m);
for(i=0;i<m;i++){
scanf("%d%d",&op,&x);
if(op==1)
insert(x);
else if(op==2)
remove(x);
else if(op==3)
printf("%d\n",grank(search(x)));
else if(op==4)
printf("%d\n",be[kth(root,x)]);
else if(op==5){
insert(x);
printf("%d\n",be[pred(search(x))]);
remove(search(x));
}
else if(op==6){
insert(x);
printf("%d\n",be[succ(search(x))]);
remove(search(x));
}
}
return 0;
}