版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Caristra/article/details/81875995
左偏树
简介:
- 左偏树中的一个节点,如果它的左子树或右子树为 ,则称它是一个外结点。
- 在左偏树中,距离( )为该点到最近外结点的距离。
- 堆性质——在非叶节点中满足 (大根堆)
- 左偏性质—— ,这样就能满足合并的复杂度
- 另外,可以想到 ,
- 不难推出,左偏树保证了每个非空儿子节点的右子树一定也是左偏树。
- 最后,一棵左偏树的高度为 ,在最右链的长度至多有 个节点。
常规操作:
- pop:弹掉该点,即合并它的左子树和右子树。
- top:返回堆顶的val。
- merge:对于需要合并的 ;先将x的右子树与y合并,再合并x。其中还要if一些满足左偏树的性质及 计算。
Code(模板):
struct node{
int l,r,val,dist;
}tree[N*20];
struct Left_Tree{
int init(){
tat=1;
tree[0]=(node){0,0,0,INF};
}
int newnode(int p){
tree[tat]=tree[p];
return tat++;
}
void merge(int x,int y){
if(!x || !y)return x+y;
if(tree[x].val>tree[y].val)swap(x,y);//取决于大、小顶堆
int o=newnode(x);
tree[o].r=merge(tree[o].r,y);//先合并右子树,因为右子树保证是左偏树
if(tree[tree[o].l].dist<tree[tree[o].r].dist)swap(tree[o].l,tree[o].r);//满足左儿子的dist>右儿子的
tree[o].dist=tree[tree[o].r].dist+1;
return o;
}
int top(int x){
return tree[x].val;
}
void push(int &x,int y,int val){
int o=newnode(0);
tree[o].val=val;
x=merge(x,o);//合并新的点
}
void pop(int &x){
int tmp=merge(tree[x].l,tree[x].r);//合并儿子
tree[x]=(node){0,0,0,INF};
}
}Ltree;
Summary:
- 左偏树是一个非常稳定的数据结构,尤其是它的合并,复杂度是很优秀的。
- 再者,一般是解决一些多维的问题,可以通过堆的排序降一维,达到一个 。