算法学习笔记(12):左偏树

左偏树

定义:

  1. 左偏树是一个堆, 具有堆的性质, 并且是左偏的
  2. 如果一个点只有左儿子或右儿子, 那么就称它为外节点, 定义一个结点的 dist 等于这个点到最近外节点的距离加 1 。特殊的, 外节点 dist 等于 1
  3. 左偏性质: 每个节点的左儿子 dist >= 右儿子 dist

操作

左偏树最重要的操作就是 合并(merge)操作, 有了这个操作, 其他操作都很简单, 和 FHQtreap 有一点像。
先看代码吧。

int merge(int x, int y) {
	if (!x || !y) return x | y;
	if (v[y] < v[x]) swap(x, y);
	rs[x] = merge(rs[x], y);
	if (dist[ls[x]] < dist[rs[x]]) swap(ls[x], rs[x]);
	dist[x] = dist[rs[x]] + 1; 
	return x;
}

merge 操作主要注意两点:

  1. 维护左偏性质。 2. 维护堆性质。

大根堆和小根堆没什么区别, 所以接下来都按小根堆来讲。
所以合并两个堆的时候, 取较小的根作为新根, 并且保留它的左儿子作为新堆的左儿子, 将它的右儿子和另一个堆递归合并作为新堆的右儿子。
可以看出每次递归, 右儿子 dist1, 所以并且根据定义, 如果这个堆大小为 n, 则根的 dist 不会大于 logn, 所以最多递归 O(logn) 层,时间复杂度就得到保证。

其他操作就很ez了。

例题

P2713 罗马游戏
模板题。两个操作。

  1. 合并两个堆。
  2. 删掉某个点所在堆的堆顶。

多了一个找根的操作, 不能暴力跳, 因为左偏树树高可以到达到 O(n) , 暴力跳t飞了, 不过可以并查集, 路径压缩一下时间复杂度 O() , 不过合并和删点的时候更新 fa 数组要注意, 很容易错。
删点的操作就直接合并它的左右儿子就行了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m, fa[N], fl[N];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
struct head{
	int ls[N], rs[N], dis[N], val[N];
	int merge(int x, int y) {
		if (!x || !y) return x | y;
		if (val[x] > val[y]) swap(x, y);
		rs[x] = merge(rs[x], y);
		if (dis[ls[x]] < dis[rs[x]]) swap(ls[x], rs[x]);
		dis[x] = dis[rs[x]] + 1;
		return x; 
	}
	void del(int x) {
		int rt = merge(ls[x], rs[x]);
		fa[x] = fa[ls[x]] = fa[rs[x]] = rt;
		dis[x] = ls[x] = rs[x] = 0;
	}
}H;
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &H.val[i]);
		fa[i] = i;
	}
	scanf("%d", &m);
	char op[5];
	for (int i = 1, x, y; i <= m; i++) {
		scanf("%s%d", op, &x);
		if (*op == 'M') {
			scanf("%d", &y);
			if (fl[x] || fl[y]) continue;
			x = find(x), y = find(y);
			if (x == y) continue;
			fa[x] = fa[y] = H.merge(x, y);
		}
		if (*op == 'K') {
			if (fl[x]) printf("0\n");
			else {
				x = find(x); 
				printf("%d\n", H.val[x]);
				H.del(x);
				fl[x] = 1;
			}
		}
	}
	return 0;
}
posted @   qqrj  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示