P3378 【模板】堆 (内含左偏树实现)
P3378 【模板】堆

题解
其实就是一个小根堆啦,STL就可以解决,但是拥有闲情雅致的我学习了Jelly_Goat的左偏树,增加了代码长度,妙啊
Solution 1 STL
STL 里面priority_queue默认是大根堆,修改一下变成小根堆

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue> using namespace std; typedef long long ll; inline int read()
{
int ans=;
char last=' ',ch=getchar();
while(ch<''||ch>'') last=ch,ch=getchar();
while(ch>=''&&ch<='') ans=ans*+ch-'',ch=getchar();
if(last=='-') ans=-ans;
return ans;
} int n,opr,x;
priority_queue<int,vector<int> ,greater<int> >h; int main()
{
n=read();
while(n--)
{
opr=read();
switch(opr)
{
case : x=read();h.push(x);break;
case : printf("%d\n",h.top() );break;
case : h.pop() ;break;
default : break ;
}
}
return ;
}
Solution 2 左偏树
什么是左偏树呢?
就是一个类似二叉堆的东西,画出来像一个二叉树

前置芝士:
1.我们定一个节点的 distance 为他距离自己子树中最右边节点的距离,下面简称 dist

所以,没有右儿子的节点dist就是0啦
2.规定左偏树中,对于一个节点来说,他的左儿子的dist > 他的右儿子的dist
然后这棵树整体就左偏啦
3.怎么计算dist???
dfs跑一遍???
其实也就是 dist [ fa ] = dist [ rson ] + 1
因为得到一个节点的dist一定是与他的右儿子有关的,既然之前知道了右儿子的dist,从右儿子转移过来,也就是dist [ rson ] + 1 ,不就得到自己的dist了吗
支持操作
1.merge 合并操作
我们在用左偏树实现小根堆(大根堆也可以实现)
假设我们要合并两个小左偏树 a,b

(1)如果一个为空,直接返回另一个不就好啦
(2)如果两个都不为空,那么我们就把他们的根节点权值较小的一个作为合并后的根节点,如果两个根节点的权值一样,那么就把dist较大的一个作为新根节点


(3)然后继续往下面合并,假设新根是a,那么把b合并到他的右子树去,然后继续处理a的左右子树
(4)get一下新根的dist
2.insert 插入操作
get一个新的点,然后把他与原来的左偏树合并
3.top 访问堆顶 (左偏树实现小/大根堆)
如果堆不为空,就输出堆顶元素,否则输出0
4.pop 弹出堆顶
也就是把左偏树的根节点去掉,合并他的左右子树
5.size 记录一共多少个元素
int cnt 记录,每次新加一个点 就cnt++,弹出一个点,就cnt--
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue> using namespace std; typedef long long ll; inline int read()
{
int ans=;
char last=' ',ch=getchar();
while(ch<''||ch>'') last=ch,ch=getchar();
while(ch>=''&&ch<='') ans=ans*+ch-'',ch=getchar();
if(last=='-') ans=-ans;
return ans;
} const int maxn=1e6+; struct Heapnode
{
int lson=,rson=,val=,dist=;
}; struct Heap
{
Heapnode tree[maxn];
int cnt=,tot=,rt=;
inline int New(int val)
{
++tot;
tree[tot].val=val;
return tot;
}
inline int set_dist(int a)
{
return tree[a].rson ? tree[tree[a].rson].dist+ : ;
}
int merge(int a,int b)
{
if(a==||b==) return a+b;
else if(tree[a].val>tree[b].val) swap(a,b);
else if(tree[a].val==tree[b].val&&tree[a].dist<tree[b].dist) swap(a,b);
tree[a].rson=merge(tree[a].rson,b);
if(tree[a].lson!=&&tree[a].rson!=){
if(tree[tree[a].lson].dist<tree[tree[a].rson].dist)
swap(tree[a].lson,tree[a].rson);
}
else if(tree[a].lson==&&tree[a].rson!=)
swap(tree[a].lson,tree[b].rson);
set_dist(a);
return a;
}
inline void insert(int val)
{
cnt++;
int b=New(val);
rt=merge(rt,b);
}
inline int top()
{
return rt?tree[rt].val:;
}
inline void pop()
{
cnt--;
int a=tree[rt].lson,b=tree[rt].rson;
rt=merge(a,b);
}
inline int size()
{
return cnt;
}
}h; int n,opr,x; int main()
{
n=read();
while(n--)
{
opr=read();
switch(opr)
{
case : x=read();h.insert(x);break;
case : printf("%d\n",h.top() );break;
case : h.pop() ;break;
default : break ;
}
}
return ;
}
P3378 【模板】堆 (内含左偏树实现)的更多相关文章
- P3377 【模板】左偏树(可并堆) 左偏树浅谈
因为也是昨天刚接触左偏树,从头理解,如有不慎之处,跪请指教. 左偏树: 什 么是(fzy说)左偏树啊? 前置知识: 左偏树中dist:表示到右叶点(就是一直往右下找,最后一个)的距离,特别的,无右节点 ...
- 洛谷 - P3377 - 【模板】左偏树(可并堆) - 左偏树 - 并查集
https://www.luogu.org/problemnew/show/P3377 左偏树+并查集 左偏树维护两个可合并的堆,并查集维护两个堆元素合并后可以找到正确的树根. 关键点在于删除一个堆的 ...
- 【BZOJ-1455】罗马游戏 可并堆 (左偏树)
1455: 罗马游戏 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1355 Solved: 561[Submit][Status][Discuss] ...
- zoj2334 Monkey King , 并查集,可并堆,左偏树
提交地址:点击打开链接 题意: N(N<=10^5)仅仅猴子,初始每仅仅猴子为自己猴群的猴王.每仅仅猴子有一个初始的力量值.这些猴子会有M次会面. 每次两仅仅猴子x,y会面,若x,y属于同一个 ...
- [APIO2012]派遣 可并堆(左偏树)
没啥说的,自底向上合并大根堆即可. 一边合并,一边贪心弹堆顶直到堆的总和不大于预算. Code: #include <cstdio> #include <algorithm> ...
- HDU3031 To Be Or Not To Be 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - HDU3031 题意概括 喜羊羊和灰太狼要比赛. 有R次比赛. 对于每次比赛,首先输入n,m,n表示喜羊羊和灰 ...
- 【bzoj2809】派遣 (左偏树)
传送门 题目分析 每个节点都是一颗(大根堆)左偏树,先按bfs序存入数组,然后倒着从底层开始:如果当前节点的子树sum > m 那么就把根节点删去,然后统计更新答案,并将这棵树和父节点合并. c ...
- 洛谷 P3377 【模板】左偏树(可并堆)
洛谷 P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或 ...
- [Luogu3377]【模板】左偏树(可并堆)
题面戳我 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数 ...
随机推荐
- Innosetup设置控制面版中的名称显示和图标
//设置控制面板中程序图标UninstallDisplayIcon={app}\logo.ico //设置控制面板中程序的名称Uninstallable=yesUninstallDisplayName ...
- 介绍两个好玩的和Github相关的Chrome扩展
1. Octotree 默认的github网页里的代码显示没有我们在IDE里看到的直观,即代码文件所在的文件夹无法以树形层级结构显示在屏幕左边. 安装Octotree之后: 方便多了. 2. Isom ...
- Heap(堆)与Stack(栈)的区别详解
在了解堆与栈之前,我们想来了解下程序的内存分配 一个编译的程序占用的内存分为以下几个部分 : 1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其 ...
- Java BIO、NIO、AIO 基础,应用场景
Java对BIO.NIO.AIO的支持: Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必 ...
- 玩转springcloud(二):注册中心-Eureka
一.简介 注册中心 注册中心是服务发现的核心.它保存了各个可用服务实例的网络地址(IP Address和Port).服务注册中心必须要有高可用性和实时更新功能. Netflix Eureka 就是一个 ...
- 关于linux一些备份、还原,压缩,归档的命令
15.1 gzipgzip(1) 是GNU的压缩程序.它只对单个文件进行压缩.基本用法如下:$ gzip filename程序执行以后,文件名会变成filename.gz,而且一般情况下大小会比原文件 ...
- XY//电容
X,Y电容都是安规电容,火线零线间的是X电容,火线与地间的是Y电容.它们用在电源滤波器里,起到电源滤波作用,分别对共模,差模工扰起滤波作用.安规电容是指用于这样的场合,即电容器失效后,不会导致电击,不 ...
- SSH环境搭建之Hibernate环境搭建篇
SSH环境搭建之Hibernate环境搭建篇 搭建有两种方式: 1.使用IntelliJ IDEA或者MyEclipse的逆向工程(关系模型 -> 对象模型),我使用的是IntelliJ IDE ...
- git 忽略部分文件
忽略: git update-index --assume-unchanged .mymetadata 取消忽略: git update-index --no-assume-unchanged
- MyBatis中#{}和${}的不同和${}的妙用(转)
突然意识到sql语句的独特语义要和代码分离,我们就不能够在代码中写sql语句!!比如我要用${}在MyBatis的sql中拼接排序类型的时候,我就不能够在Java代码中直接写参数字符串为Ord ...