[note]左偏树(可并堆)
左偏树(可并堆)https://www.luogu.org/problemnew/show/P3377
题目描述
一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:
操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)
操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)
输入格式:
第一行包含两个正整数N、M,分别表示一开始小根堆的个数和接下来操作的个数。
第二行包含N个正整数,其中第i个正整数表示第i个小根堆初始时包含且仅包含的数。
接下来M行每行2个或3个正整数,表示一条操作,格式如下:
操作1 : 1 x y
操作2 : 2 x
输出格式:
输出包含若干行整数,分别依次对应每一个操作2所得的结果。
输入样例:
5 5
1 5 4 2 3
1 1 5
1 2 5
2 2
1 4 2
2 2
输出样例:
1
2
说明
当堆里有多个最小值时,优先删除原序列的靠前的,否则会影响后续操作1导致WA。
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=1000,M<=1000
对于100%的数据:N<=100000,M<=100000
样例说明:
初始状态下,五个小根堆分别为:{1}、{5}、{4}、{2}、{3}。
第一次操作,将第1个数所在的小根堆与第5个数所在的小根堆合并,故变为四个小根堆:{1,3}、{5}、{4}、{2}。
第二次操作,将第2个数所在的小根堆与第5个数所在的小根堆合并,故变为三个小根堆:{1,3,5}、{4}、{2}。
第三次操作,将第2个数所在的小根堆的最小值输出并删除,故输出1,第一个数被删除,三个小根堆为:{3,5}、{4}、{2}。
第四次操作,将第4个数所在的小根堆与第2个数所在的小根堆合并,故变为两个小根堆:{2,3,5}、{4}。
第五次操作,将第2个数所在的小根堆的最小值输出并删除,故输出2,第四个数被删除,两个小根堆为:{3,5}、{4}。
故输出依次为1、2。
给大家介绍一篇左偏树讲解
以下摘自国集2005论文集
左偏树(Leftist Tree)
是一种可并堆的实现。左偏树是一棵二叉树,它的节点除了和二叉树的节点一样具有左右子树指针外,还有两个属性:点权(键值)和距离(dist).
左偏树满足下面两条基本性质:
[性质1] 节点的键值小于或等于它的左右子节点的键值.
这条性质又叫堆性质。符合该性质的树是堆有序的。
有了性质1,我们可以知道左偏树的根节点是整棵树的最小节点,于是我们可以在O(1) 的时间内完成取最小节点操作。
[性质2] 节点的左子节点的距离不小于右子节点的距离.
即dist(left(i))≥dist(right(i)) 这条性质称为左偏性质。
性质2是为了使我们可以以更小的代价在优先队列的其它两个基本操作(插入节点、删除最小节点)进行后维持堆性质。
这两条性质是对每一个节点而言的,因此可以简单地从中得出,左偏树的左右子树都是左偏树。
由这两条性质,我们可以得出左偏树的定义:左偏树是具有左偏性质的堆有序二叉树。
习惯上常用根节点序号表示左偏树
#define RG register
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e5+5;
inline int read()
{
RG int x=0,w=1;RG char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
int n,m;
int num[N],ls[N],rs[N],root[N],dist[N];//num[]为每个点的值,ls[]和rs[]为左右儿子,root[]表示该节点所在堆的堆顶编号(左偏树根节点),dist[i]表示节点i节点i到它的后代中最近的外节点所经过的边数[某节点称为外节点,当且仅当该节点的左子树或右子树为空].
bool del[N];//判断点是否被删除
int find(int x){return x==root[x]?x:root[x]=find(root[x]);}//并查集找根节点
int Merge(int a,int b)
{
if(!a||!b)return a+b;//若某一子树为空,返回另一棵子树
if(num[a]>num[b]||(num[a]==num[b]&&a>b))swap(a,b);//维护小根堆[权值相同,序号优先]
rs[a]=Merge(rs[a],b);//每次将a的右子树与b合并
if(dist[ls[a]]<dist[rs[b]])swap(ls[a],rs[a]);//交换左右儿子[保证左偏]
dist[a]=dist[rs[a]]+1;
return a;
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)num[i]=read(),root[i]=i;
while(m--)
{
int f=read();
if(f==1)
{
int a=read(),b=read();
int x=find(a),y=find(b);
if(x==y||del[a]||del[b])continue;
root[x]=root[y]=Merge(x,y);//修改根节点
}
else
{
int x=read();
if(del[x]){printf("-1\n");continue;}
x=find(x);
printf("%d\n",num[x]);
del[x]=true;
root[x]=Merge(ls[x],rs[x]);//修改根节点
if(ls[x]==root[x])root[ls[x]]=ls[x];//将根节点的根置为自己[防止find()递归出错]
if(rs[x]==root[x])root[rs[x]]=rs[x];//将根节点的根置为自己
ls[x]=rs[x]=0;//清空被删除点的左右儿子
}
}
return 0;
}
[note]左偏树(可并堆)的更多相关文章
- bzoj2809 [Apio2012]dispatching——左偏树(可并堆)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2809 思路有点暴力和贪心,就是 dfs 枚举每个点作为管理者: 当然它的子树中派遣出去的忍者 ...
- HDU3031 To Be Or Not To Be 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - HDU3031 题意概括 喜羊羊和灰太狼要比赛. 有R次比赛. 对于每次比赛,首先输入n,m,n表示喜羊羊和灰 ...
- HDU5818 Joint Stacks 左偏树,可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - HDU5818 题意概括 有两个栈,有3种操作. 第一种是往其中一个栈加入一个数: 第二种是取出其中一个栈的顶 ...
- BZOJ 4003: [JLOI2015]城池攻占 左偏树 可并堆
https://www.lydsy.com/JudgeOnline/problem.php?id=4003 感觉就是……普通的堆啊(暴论),因为这个堆是通过递归往右堆里加一个新堆或者新节点的,所以要始 ...
- Monkey King(左偏树 可并堆)
我们知道如果要我们给一个序列排序,按照某种大小顺序关系,我们很容易想到优先队列,的确很方便,但是优先队列也有解决不了的问题,当题目要求你把两个优先队列合并的时候,这就实现不了了 优先队列只有插入 删除 ...
- BZOJ 5494: [2019省队联测]春节十二响 (左偏树 可并堆)
题意 略 分析 稍微yy一下可以感觉就是一个不同子树合并堆,然后考场上写了一发左偏树,以为100分美滋滋.然而发现自己傻逼了,两个堆一一对应合并后剩下的一坨直接一次合并进去就行了.然鹅我这个sb把所有 ...
- [luogu3377][左偏树(可并堆)]
题目链接 思路 左偏树的模板题,参考左偏树学习笔记 对于这道题我是用一个并查集维护出了哪些点是在同一棵树上,也可以直接log的往上跳寻找根节点 代码 #include<cstdio> #i ...
- BZOJ1455 罗马游戏 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1455 题意概括 n个人,2种操作. 一种是合并两个人团,一种是杀死某一个人团的最弱的人. 题解 左 ...
- BZOJ2333 [SCOI2011]棘手的操作 堆 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2333 题意概括 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i ...
随机推荐
- Maven编译Java程序配置
Hive 需要在工程里添加的Jar包: hadoop-2.2.0/share/hadoop/common/hadoop-common-2.2.0.jar $HIVE_HOME/lib/hive-exe ...
- 14. Android框架和工具之 ImageLoader(图片加载)
1. 这个图片加载框架网友很多都已经使用过,而且分析也很到位,这里我就不写了,直接引用别人,尊重别人的劳动成果. 2. 参考如下: (1)Android 开源框架Universal-Image-Loa ...
- Guava包学习-Multimap
它和上一章的MultiSet的继承结果很相似,只不过在上层的接口是Multimap不是Multiset. Multimap的特点其实就是可以包含有几个重复Key的value,你可以put进入多个不同v ...
- 【vue】饿了么项目-使用webpack打包项目
1.vue cli给我们提供了npm run build命令打包项目,在packa.json文件中scripts对象中有build属性,当我们执行npm run build时,就执行build对应的& ...
- 程序员职业规划(一篇来自"阿里Java工程师"对工作3年左右程序员的职业建议和应该掌握的职业技能)
程序员的三个阶段(转载) 第一阶段:三年 我认为三年对于程序员来说是第一个门槛,这个阶段将会淘汰掉一批不适合写代码的人. 这一阶段,我们走出校园,迈入社会,成为一名程序员,正式从书本上的内容迈向真正的 ...
- DPDK运行出现EAL Error reading from file descriptor 23 Input output error
原因 dpdk不支持该网卡导致,需要修改一行代码,跳过dpdk pci 检查. 解决方法 修改lib/librte_eal/linuxapp/igb_uio/igb_uio.c 将文件中该行修改 pc ...
- 在CentOS上安装node.js的时候报错:No acceptable C compiler found!解决办法
在CentOS上安装node.js的时候报错:No acceptable C compiler found! 原因:没有c编译器. 解决办法:安装GCC 命令如下: #yum install gcc ...
- Notes 20180309 : String第一讲_char的可读序列
实际上在写本文之前,我曾考虑是先探讨面向对象,还是先选择String和Arrays,最后还是选择了后者,并非是面向对象对我们不重要,相反它是Java的灵魂所在,之所以这样的安排是因为这两个是在是我们程 ...
- Oracle分析函数巧妙使用
在 Oracle中使用Sql必须弄懂分析函数 Oracle开发专题之:分析函数(OVER) 1 Oracle开发专题之:分析函数2(Rank, Dense_rank, row_number) 6 Or ...
- Web—13-判断网站请求来自手机还是pc浏览器
判断网站请求来自手机还是pc浏览器 #判断网站来自mobile还是pc def checkMobile(request): """ demo : @app.route(' ...