左偏树(可并堆)详解及有关模板

这几天搞了几道左偏树的题,主要是开阔眼界,堆还能这样写,下面详细讲解一下左偏树的特点及其应用。

首先从可并堆的定义讲起:

可并堆,就是一种支持合并的堆,如果用普通的二叉堆来实现合并操作,则O(n)的合并时间复杂度是一个瓶颈,这是就要引入左偏树(Leftist Tree),其实二项堆和Fibonacci堆也是很优秀的可并堆,这里只讲其中的左偏树。

左偏树定义:

左偏树是一种可并堆的实现,左偏树是一棵二叉树,除了左右子树指针外,还有键值和dist距离,距离则是这样定义的:

首先定义节点i为外节点当且仅当节点i的左子树或右子树为空,节点i的距离dist[i]是在节点i到它的子树中,最近的外节点所经过的边数。如果节点i为外节点,则它的距离为0,如果节点i为空节点,则它的距离为-1。

左偏树满足的性质:

性质1、由大小根堆来定,即二叉堆的性质。

性质2、节点左子节点的距离不小于右子节点的距离(左偏树名称的由来)

性质3、节点距离等于它的右子节点的距离加1

然后就有一些引理和定理:

引理1:若左偏树的距离为一定值,则节点数最少的左偏树是完全二叉树

定理1:若一棵左偏树的距离为k,则这棵左偏树至少有2^k+1-1个节点

从而可以得出性质4:一棵N个节点的左偏树距离最多为下取整log(N+1) -1。

接下来是合并操作,很好理解,贴上模板差不多就知道了

int merge(int x,int y){
	if(!x) return y;
	if(!y) return x;
	if(heap[x].key>heap[y].key) swap(x,y);
	heap[x].r=merge(heap[x].r,y);
	if(heap[heap[x].r].key>heap[heap[x].l].key) swap(heap[x].l,heap[x].r);
	heap[x].dist=heap[heap[x].r].dist+1;
	return x;
}

删除操作很简单,比如删除节点i,只要将左子树和右子树合并,然后修改它们的父亲即可。

inline void erase(int u){
    int l=heap[u].left,r=heap[u].right;
    heap[u].key=-1;heap[l].fa=0;heap[r].fa=0;
    merge(l,r);
    return;
}

两个主要操作已经讲好了,其他操作都是基于这两个操作的,就不加赘述,详细的可以见国家集训队论文2005黄源河的论文,讲的很好懂。

接下来就是多做题了,明白了定义模板做题也是必要的O(∩_∩)O哈哈~



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值