堆(左偏树)

左偏树

定义一个节点的高度为到叶子节点的最短距离。
一棵左偏树需要满足几个性质:
\(1.\)它是一个堆。
\(2.\)一个节点的左儿子的高度\(\ge\)右儿子的高度。
\(3.\)一个节点的高度\(=\)右儿子的高度\(+1\)。
由此可以得出一个节点数为\(n\)的左偏树的高度为\(\log (n+1)-1\)。
每个节点需要维护左右儿子和权值。
实际上要维护的是左偏树森林,所以同时用并查集维护每个节点所属左偏树的根。
左偏树只有一个核心操作:merge。

merge

merge实现合并两个节点所在的左偏树。
假如我们要合并的两棵左偏树的根是\(u,v\),不妨设\(val_u\)小于\(val_v\)。
然后我们递归合并\(u\)的右儿子和\(v\)。
可以发现我们递归合并之后右儿子的高度最多\(+1\),如果此时右儿子的高度大于左儿子了那就交换左右儿子。
最后维护一下并查集。

int merge(int u,int v)
{
    if(!u||!v) return u+v;
    if(val[u]>val[v]||(val[u]==val[v]&&u>v)) swap(u,v);
    ch[u][1]=merge(ch[u][1],v);
    if(h[ch[u][0]]<h[ch[u][1]]) swap(ch[u][0],ch[u][1]);
    return fa[ch[u][0]]=fa[ch[u][1]]=fa[u]=u,h[u]=h[ch[u][1]]+1,u;
}

pop

pop实现弹出某个节点所在左偏树的根。
直接把根\(p\)的左右儿子合并起来就好了。
但是因为原左偏树中有些点在并查集中只连到了\(p\),所以要把\(p\)在并查集里连到新的左偏树的根上去。

void pop(int p){val[p]=-1,fa[lc]=lc,fa[rc]=rc,fa[p]=merge(lc,rc);}

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12164114.html

时间: 2024-11-04 05:13:34

堆(左偏树)的相关文章

[BZOJ1455]罗马游戏-斜堆/左偏树-并查集(+数据生成器)

Problem 遗产 题目大意 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的团合并成一个团.如果i, j有一个人是死人,那么就忽略该命令. 2. Kill(i).把i所在的团里面得分最低的人杀死.如果i这个人已经死了,这条命令就忽略. 皇帝希望他每发布一条kill命令

【BZOJ 1455】 1455: 罗马游戏 (可并堆-左偏树+并查集)

1455: 罗马游戏 Description 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的团合并成一个团.如果i, j有一个人是死人,那么就忽略该命令. 2. Kill(i).把i所在的团里面得分最低的人杀死.如果i这个人已经死了,这条命令就忽略. 皇帝希望他每发布一

浅谈左偏树在OI中的应用

Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log(|A|)+\log(|B|)\),极限数据下显然是要T爆的. 所以我们考虑使用一种性价比最高的可并堆--左偏树,它的思想以及代码都挺简单而且效率也不错. 学习和参考自这里 What is Leftist Tree 左偏树,顾名思义就是像左偏的树,但是这样抽象的表述肯定是不符合我们学OI的人的背板子

【模板】左偏树(可并堆)

题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作) 操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示一开始小根堆的个数和接下来操作的个数. 第二行包含N个正整数,其中第i个正整数表示第i个小根堆初始时包含且仅包

【BZOJ-1455】罗马游戏 可并堆 (左偏树)

1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1355  Solved: 561[Submit][Status][Discuss] Description 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的

zoj2334 Monkey King , 并查集,可并堆,左偏树

提交地址:点击打开链接 题意:  N(N<=10^5)只猴子,初始每只猴子为自己猴群的猴王,每只猴子有一个初始的力量值.这些猴子会有M次会面.每次两只猴子x,y会面,若x,y属于同一个猴群输出-1,否则将x,y所在猴群的猴王的力量值减半,然后合并这两个猴群.新猴群中力量值最高的为猴王.输出新猴王的力量值. 分析:涉及集合的查询,合并,取最值. 利用并查集和左偏树即可解决. #include <cstdio> #include <cstring> #include <io

P3377 【模板】左偏树(可并堆)

P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作) 操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示一开始小根堆的个数和接下来操作的个数. 第二行包含N个正整数,其中第i个

左偏树(可并堆)

"左偏"树? 左偏树其实是一种可并堆,它可以 \(O(log_2 n)\) 合并两个堆. 那左偏?也就是说他左边肯定有什么东西比右边大-- 别着急,在左偏树上有一个叫距离的东西: 个点的距离,被定义为它子树中离他最近的外节点到这个节点的距离(这与树的深度不同) 其中我们定义一个节点为外节点,当且仅当这个节点的左子树和右子树中的一个是空节点.(注意外节点不是叶子节点) 这幅图中的这三个节点都是外节点. 而左偏树指的就是就是一个节点的左儿子的距离一定大于等于右儿子的距离. 例如下面就是一棵

luogu_P3377 左偏树(可并堆)

传送门:https://www.luogu.org/problem/P3377 左偏树:左偏!也就是下面这种左边大,右边小的树 可并堆:可以合并的堆(堆:维护最值的数据结构) 核心(细节): 先来代码 int merge(int x,int y){ if(!x||!y) return x+y; if(val[x]>val[y] || (val[x]==val[y]&&x>y)) swap(x,y); rs[x]=merge(rs[x],y); rt[rs[x]]=rt[ls[x

P3377 【模板】左偏树(可并堆) 左偏树浅谈

因为也是昨天刚接触左偏树,从头理解,如有不慎之处,跪请指教. 左偏树: 什 么是(fzy说)左偏树啊? 前置知识: 左偏树中dist:表示到右叶点(就是一直往右下找,最后一个)的距离,特别的,无右节点的为0. 堆:左偏树是个堆. 关于左偏性质:可以帮助堆合并(研究深了我也不懂的,看代码理解) 对于任意的节点,dist[leftson]>=dist[rightson],体现了左偏性质. 同理可得:对于任意右儿子的父亲节点的dist自然等于右儿子的dist+1喽 关于各种操作: merge: 是插入