首页 > 其他分享 >可并堆

可并堆

时间:2024-07-01 09:42:34浏览次数:1  
标签: val rs int 合并 节点 左偏

左偏树(Leftist Tree)

定义

外节点:只有一个儿子或没有儿子的节点。

距离:一个节点到离他最近的外节点的距离,即两节点之间的路径权值和。特别地,外节点的距离为 \(0\),空节点的距离为 \(-1\).

image

左偏树:满足如下性质的二叉树:

  1. 堆性质:任何节点的权值小于等于儿子节点的权值,即 \(val_{fa_i} \le val_i\).
  2. 左偏性质:任何节点的左儿子距离大于等于右儿子距离,即 \(d_{ls_i} \ge d_{rs_i}\).

推论:

  1. 任意节点的距离等于右儿子距离 \(+ 1\),即 \(d_i = d_{rs_i} + 1\).
  2. 根节点的距离为 \(d\) 的左偏树,节点数不少于 \(2^{d+1} - 1\).

操作

合并(Merge)

合并根节点为 \(x, y\) 的两颗左偏树。

  • 假设 \(val_x \le val_y\),那么根节点一定为 \(x\),否则为 \(y\).
  • 需要递归合并 \(rs_x\) 和 \(y\),并将新树的根作为 \(rs_x\).
  • 合并完成后,\(d_{rs_x}\) 可能会变,为了保证左偏性质,若 \(d_{ls_x} < d_{rs_x}\),那么交换 \(x\) 的左右儿子。
  • 更新 \(d_x\),以 \(x\) 为合并后的根节点。
int merge(int x, int y)
{
	if(!x || !y) return x + y; // 若一个堆为空则返回另一个堆
	if(val[x] > val[y]) swap(x, y); // 取值较小的作为根,满足堆性质
	r[x] = merge(r[x], y), fa[r[x]] = x; // 递归合并右儿子与另一个堆
	if(dis[l[x]] < dis[r[x]]) swap(l[x], r[x]); // 若不满足左偏性质则交换左右儿子
	dis[x] = dis[r[x]] + 1;
	return x;
}

插入(Push)

合并一个只有一个节点的左偏树。

弹出(Pop)

  • 将根的左右节点合并,然后将合并后的节点设为根。
int pop(int x)
{
	int ls = l[x], rs = r[x];
	int y = merge(ls, rs);
	fa[y] = 0;
	return y;
}

删除(Del)

  • 将左右儿子合并后挂到父节点下,若父节点不满足左偏性质,则一路调整。

建树(Build)

  • 暴力插入时间复杂度为 \(O\left(n \log n\right)\).
  • 利用队列优化,两个两个合并,时间复杂度 \(O(n)\).

标签:,val,rs,int,合并,节点,左偏
From: https://www.cnblogs.com/Heartquakes/p/18277386

相关文章