算法学习笔记(12):左偏树
1.算法学习笔记(1):CDQ分治2.算法学习笔记(2):分块3.算法学习笔记(3):莫队算法4.算法学习笔记(4):FHQ平衡树(无旋平衡树)5.算法学习笔记(5):AC自动机6.算法学习笔记(6):优秀trick和性质合集7.算法学习笔记(7):数论8.算法学习笔记(9):第k大问题合集9.算法学习笔记(10):各种序的美好性质10.算法学习笔记(11):历史版本和线段树
11.算法学习笔记(12):左偏树
12.算法学习笔记(13):同余最短路13.算法学习笔记(14):区间最值操作和历史最值问题14.算法学习笔记(15): Splay树15.算法学习笔记(16):Link Cut Tree16.算法学习笔记(17):Slope trick17.算法学习笔记(18):珂朵莉树18.算法学习笔记(20):网络流19.算法学习笔记(21):数论分块20.算法学习笔记(22):莫比乌斯反演21.算法学习笔记(23):杜教筛22.算法学习笔记(24):筛法23.暑假集训学习笔记(1):lxl DS Day 124.暑假集训学习笔记(2):lxl DS Day 225.暑假集训学习笔记(3):lxl DS Day 326.多项式笔记27.生成函数笔记28.插头DP29.DP选讲做题记录 by 付乙淼30.拓展摩尔投票31.图论知识总结左偏树
定义:
- 左偏树是一个堆, 具有堆的性质, 并且是
左偏的 - 如果一个点只有左儿子或右儿子, 那么就称它为外节点, 定义一个结点的
等于这个点到最近外节点的距离加 。特殊的, 外节点 等于 。 - 左偏性质: 每个节点的左儿子
>= 右儿子 。
操作
左偏树最重要的操作就是 合并(
先看代码吧。
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;
}
- 维护左偏性质。 2. 维护堆性质。
大根堆和小根堆没什么区别, 所以接下来都按小根堆来讲。
所以合并两个堆的时候, 取较小的根作为新根, 并且保留它的左儿子作为新堆的左儿子, 将它的右儿子和另一个堆递归合并作为新堆的右儿子。
可以看出每次递归, 右儿子
其他操作就很ez了。
例题
P2713 罗马游戏
模板题。两个操作。
- 合并两个堆。
- 删掉某个点所在堆的堆顶。
多了一个找根的操作, 不能暴力跳, 因为左偏树树高可以到达到
删点的操作就直接合并它的左右儿子就行了。
代码
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App