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酱带大家康康 无所不在的非线性数据结构之一:树形结构的特点和应用. 树形结构,是指:数据元素之间的关系像一颗树的数据结构.我们看图说话: 它具有以下特点: ...
随机推荐
- redis 获取方式和安装(windows)
Windows redis :https://github.com/MSOpenTech/redis/releases Linux redis :https://github.com/phpredis ...
- Oracle数据库应用系统结构
在安装.部署oracle数据库软件时,需要根据不同应用结构(即硬件平台.操作系统平台)采用不同的方法(基本安装.高级安装),下面介绍几种常见的应用结构. 1.应用系统的数据接口 客户端应用程序或应用服 ...
- 图片水印工具类java
关于jar包的导入我就不多说了,我会把引入的jar包显示出来,大家自行Google package com.net.util; import java.awt.AlphaComposite; impo ...
- 搜索(BFS、DFS、回溯)
这类题是最简单的了都是一个套路,不像动态规划一类题一个套路,没做过就是不会也极难想出来. 一.BFS 解决的问题:用来初始点解决到指定点的最短路径问题,因为图的每一层上的点到初始点的距离相同.(注意是 ...
- fiddler笔记:主菜单栏
主菜单可以启动几乎所有的fiddler功能.菜单系统通过FiddlerScript或Extensions进行扩展和增强. 1.File菜单 File菜单主要是用来启动和停止web流量的捕获,也可以加载 ...
- Django的URLconf
URL 概要 我们要在Django项目中为应用程序设计URL,我们可以创建一个名为URLconf(通常为urls.py)的Python模块.这个模块是纯Python代码,是一个简单的正则表达式到Pyt ...
- BFS以及hash表判重的应用~
主要还是讲下hash判重的问题吧 这道题目用的是除法求余散列方式 前几天看了下算法导论 由于我们用的是线性再寻址的方式来解决冲突问题 所以hash表的大小(余数的范围)要包含我们要求的范围 对mod的 ...
- 9-MySQL DBA笔记-测试实践
第9章 测试实践 在第8章中介绍了测试所需要的理论知识,本章将为读者讲述实际的测试过程.实际测试一般包括硬件测试.MySQL基准测试及应用服务压力测试,下面将分别讲述这三方面的内容.此外,测试工具的选 ...
- vue 通过 name 和 params 进行调整页面传参刷新参数丢失问题&vue路由可选参数
vue 通过 name 和 params 进行调整页面传参刷新参数丢失问题 router.js: export default new Router({ routes: [ { path: '/', ...
- luogu题解 P4092 【[HEOI2016/TJOI2016]树】树链剖分
题目链接: https://www.luogu.org/problemnew/show/P4092 瞎扯--\(O(Q \log^3 N)\)解法 这道先yy出了一个\(O(Q \log^3 N)\) ...