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个数 ...
随机推荐
- 什么是TCP/IP协议和举例
一张图+说明,彻底理解TCP/IP协议是个什么玩意儿! 相关图片:https://www.cnblogs.com/andy9468/p/10096606.html 说明:1.应用层常见协议或命令:HT ...
- 阿里云Ubuntu下tomcat8.5配置SSL证书
环境 阿里云ubuntu(18.04)服务器 阿里云申请的域名 Tomcat8.5.7 jdk1.8 免费型SSL证书 SSL证书申请 登录阿里云的官网,登录后在菜单中选择SSL证书(应用安全) 进入 ...
- Django:forms局部函数、cookie、sesion、auth模块
一.forms组件 二.cookie和session组件 三.auth组件 一.forms组件 1.校验字段功能 针对一个实例:注册用户讲解 模型:models class UserInfo(mode ...
- [shell] shell echo打印换行的方法
echo要支持同C语言一样的\转义功能,只需要加上参数-e,如下所示: echo -e hello \n echo \n
- Python3+Appium学习笔记03-启动app
这个是appium相关的官方api地址:http://appium.io/docs/en/about-appium/api/ 如同selenium进行自动化测试时,需要先创建一个浏览器实例一样.在使用 ...
- kettle 数据抽取时会出现 无法插入NULL
kettle 数据抽取时会出现 无法插入NULL,其实是空字符串,原因是kettle默认不区分空字符串和NULL. 解决办法: 修改kettle.properties 文件:
- vector简单使用
在刷ccf题的时候日常做完去网上查看别的同学怎么做的 发现有使用vector后三十几行代码就写出来的,虽然时间复杂度和我一样十几毫秒,but !我看中了它的代码量啊!多么的少啊! 所以百度了vecto ...
- Educational Codeforces Round 22 B. The Golden Age(暴力)
题目链接:http://codeforces.com/contest/813/problem/B 题意:就是有一个数叫做不幸运数,满足题目的 n = x^a + y^b,现在给你一个区间[l,r],让 ...
- 深入了解java线程池(转载)
出处:http://www.cnblogs.com/dolphin0520/ 本文归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责 ...
- HDU 6046 - hash | 2017 Multi-University Training Contest 2
思路来自题解和一些博客 最麻烦的是样例没啥用- - /* HDU 6046 - hash [ hash,鸽巢 ] | 2017 Multi-University Training Contest 2 ...