P3377 【模板】左偏树(可并堆) 左偏树浅谈
因为也是昨天刚接触左偏树,从头理解,如有不慎之处,跪请指教。
左偏树:
什 么是(fzy说)左偏树啊?
前置知识:
左偏树中dist:表示到右叶点(就是一直往右下找,最后一个)的距离,特别的,无右节点的为0。
堆:左偏树是个堆。
关于左偏性质:可以帮助堆合并(研究深了我也不懂的,看代码理解)
对于任意的节点,dist[leftson]>=dist[rightson],体现了左偏性质。
同理可得:对于任意右儿子的父亲节点的dist自然等于右儿子的dist+1喽
关于各种操作:
merge:
是插入操作的函数,具体步骤如下:
1.对于两个堆x,y,判断x,y是否为0,如果有一个为0,相当于没合并,直接返回另一个有元素的堆。
2.找到value值更大的那个堆头放到顶上,如果value值一样的话就按堆顶编号来排序。为了方便代码实现,我们可以规定x为符合条件(小,大跟堆)的那个堆头,然后如果y符合条件就交换x,y值。
3.既然堆头找着了,就可以进一步的合并堆头右儿子和y堆了(为了尽量保证左偏的性质)。如此递归下去,随着新堆头被一次次确定,最终这个堆会被一点一点融合到另一个堆中。
4.但是,鉴于合成完后,不一定能够保证左子树的dist值一定会比右字数的大,我们只要判断一下是否符合左偏性质,如果不符合,就交换一下当前节点左右子树就行了。因为是递归执行,从更深节点一层一层上来,那么必然的整个堆会符合左偏性质。然后更新一下dist为右子树dist+1.一次merge完成。
代码:
- inline int merge(int x, int y)
- {
- if(!x||!y)return x+y;
- if(tree[x].value>tree[y].value||(tree[x].value==tree[y].value&&x>y))swap(x,y);
- rs=merge(rs,y);
- if(tree[ls].dist<tree[rs].dist)swap(ls, rs);tree[ls].rt=tree[rs].rt=tree[x].rt=x,tree[x].dist=tree[rs].dist+;
- //更新dist
- return x ;
- }
2.pop弹出函数:
弹出函数,即弹出堆顶。方法很简单:没有了堆顶,整个左偏树就被分为了两个小的左偏树。我们只要忽略掉堆顶合并(merge)两个小的左偏树即可。
注意事项:不要忘了堆顶元素相关信息还原为初始。
代码:
- inline void pop(int x)//弹出x为堆顶的堆
- {
- tree[x].value=-,tree[ls].rt=ls,tree[rs].rt=rs;
- tree[x].rt=merge(ls,rs);
- }
3.get函数:
没啥可说的,就是并查集找父亲并且路径压缩。
代码:
- int get(int x)
- {
- return x==tree[x].rt?x:tree[x].rt=get(tree[x].rt);
- }
三个函数代码已经完结。
main函数内根据题意进行模拟即可。
总代码:
- #include<queue>
- #include<iostream>
- #include<cstdlib>
- #include<cstring>
- #include<cstdio>
- #define N 100003
- #define ls tree[x].son[0]
- #define rs tree[x].son[1]
- using namespace std;
- int read()
- {
- int ans=;
- char ch=getchar(),last=' ';
- while(ch<''||ch>'')last=ch,ch=getchar();
- while(ch>=''&&ch<='')ans=(ans<<)+(ans<<)+ch-'',ch=getchar();
- return last=='-'?-ans:ans;
- }
- inline void swap(int &x,int &y)
- {
- x^=y^=x^=y;
- }
- int n,num,hea[N],t,judge,b,c;
- struct tre{
- int son[],rt,dist,value;
- }tree[N];
- inline int merge(int x, int y)
- {
- if(!x||!y)return x+y;
- if(tree[x].value>tree[y].value||(tree[x].value==tree[y].value&&x>y))swap(x,y);
- rs=merge(rs,y);
- if(tree[ls].dist<tree[rs].dist)swap(ls, rs);tree[ls].rt=tree[rs].rt=tree[x].rt=x,tree[x].dist=tree[rs].dist+;
- //更新dist
- return x ;
- }
- int get(int x)
- {
- return x==tree[x].rt?x:tree[x].rt=get(tree[x].rt);
- }
- inline void pop(int x)//弹出x为堆顶的堆
- {
- tree[x].value=-,tree[ls].rt=ls,tree[rs].rt=rs;
- tree[x].rt=merge(ls,rs);
- }
- int main(){
- n=read(),t=read();tree[].dist=-;
- for (int i=;i<=n;i++)
- tree[i].rt=i,scanf("%d",&tree[i].value);//并差集初始化+输入
- for (int i=;i<=t;i++){
- judge=read(),b=read();
- if (judge==){
- c=read();
- if (tree[b].value==-||tree[c].value==-) continue ;
- int f1=get(b),f2=get(c);if(f1!=f2)tree[f1].rt=tree[f2].rt=merge(f1,f2);//合并操作
- }
- else {
- if(tree[b].value==-)printf("-1\n") ;
- else printf("%d\n",tree[get(b)].value),pop(get(b)) ;//输出并弹出
- }
- }
- return ;
- }
完结。
彩蛋:有趣的东西:
极度真实的左偏树。
来自dalao
P3377 【模板】左偏树(可并堆) 左偏树浅谈的更多相关文章
- 【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)
2333: [SCOI2011]棘手的操作 Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边 ...
- 浅谈Java中的栈和堆
人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...
- [note]左偏树(可并堆)
左偏树(可并堆)https://www.luogu.org/problemnew/show/P3377 题目描述 一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 ...
- Monkey King(左偏树 可并堆)
我们知道如果要我们给一个序列排序,按照某种大小顺序关系,我们很容易想到优先队列,的确很方便,但是优先队列也有解决不了的问题,当题目要求你把两个优先队列合并的时候,这就实现不了了 优先队列只有插入 删除 ...
- bzoj2809 [Apio2012]dispatching——左偏树(可并堆)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2809 思路有点暴力和贪心,就是 dfs 枚举每个点作为管理者: 当然它的子树中派遣出去的忍者 ...
- 浅谈左偏树在OI中的应用
Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log ...
- 笔试算法题(46):简介 - 二叉堆 & 二项树 & 二项堆 & 斐波那契堆
二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者 ...
- 洛谷——P3919 【模板】可持久化数组(可持久化线段树/平衡树)
P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...
- 浅谈树形结构的特性和应用(上):多叉树,红黑树,堆,Trie树,B树,B+树...
上篇文章我们主要介绍了线性数据结构,本篇233酱带大家康康 无所不在的非线性数据结构之一:树形结构的特点和应用. 树形结构,是指:数据元素之间的关系像一颗树的数据结构.我们看图说话: 它具有以下特点: ...
随机推荐
- OpenCV.资料(20190717)
1.opencv将图片转换为视频 - zeng_haoyu的博客 - CSDN博客.html(https://blog.csdn.net/hy13684802853/article/details/8 ...
- matplotlib画图总结--多子图布局
1.subplot布局 subplot(nrows, ncols, index, **kwargs) subplot(pos, **kwargs) subplot(ax) x=[1,2,3] valu ...
- find the mincost route【无向图最小环】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1599 Problem Description 杭州有N个景区,景区之间有一些双向的路来连接,现在860 ...
- Collection集合常用的功能
package demo06; import java.util.ArrayList;import java.util.Collection; /** java.util接口 Collection&l ...
- RxJava基本使用
更多文章请点击链接:http://77blogs.com/?p=162 转载请标明出处:https://www.cnblogs.com/tangZH/p/12088300.html,http://77 ...
- superset部署
superset功能概述: 丰富的数据可视化集 易于使用的界面,用于探索和可视化数据 创建和共享仪表板 与主要身份验证提供程序集成的企业级身份验证(通过Flask AppBuilder进行数据库,Op ...
- 最长回文 HDU - 3068(马拉车算法)
Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入 ...
- 剑指offer46:圆圈中最后剩下的数字(链表,递归)
1 题目描述 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随 ...
- 基于DNS(Consul)高可用
DNS 推荐从Bind-DLZ入手,资料多可控制度更好(查询DNS记录SQL可定制)据说性能差 Bind-DLZhttps://www.cnblogs.com/saneri/p/8178065.htm ...
- linux实现一个定时任务
设置定时任务删除logs脚本数据 编写脚本 touch cleanLogs.sh #! /bin/sh -name "*.log*" -exec rm -f {} \; 使用r ...