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个数 ...
随机推荐
- easyUi 的form和validate组件
以下代码不能运行,只是我在学习过程中记录的笔记,但代码可以用!!! 可以按照需要截取. <%@ page language="java" contentType=" ...
- 安卓开发之ListView入门
<!--这个地方最好用match_parent 这样效率高--> <ListView android:layout_width="match_parent" an ...
- 少勇 #import和@class的区别
#import与@class的区别1.import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告 ...
- Matlab修改数值格式/精度/小数位数
————————————命令行方法————————————— 直接在命令行中输入以下命令,但该命令不影响数据的存储形式和计算精度,下次还需进行修改. format 默认格式 format short ...
- ConcurrentDictionary源码概读
ConcurrentDictionary的数据结构主要由Tables和Node组成,其中Tables包括桶(Node,节点)数组.局部锁(Local lock).每个锁保护的元素数量(PerLock) ...
- [转载]pytest学习笔记
pytest学习笔记(三) 接着上一篇的内容,这里主要讲下参数化,pytest很好的支持了测试函数中变量的参数化 一.pytest的参数化 1.通过命令行来实现参数化 文档中给了一个简单的例子, ...
- ProjectEuler237 Tours on a 4 x n playing board
思路是这样的 插头dp-->打表-->OEIS查表-->通项公式-->矩阵快速幂优化线性递推 OEIS竟然有这个东西的生成函数啊 答案为15836928 这是最终代码 #inc ...
- Linux初始化脚本
以下脚本用于linux系统的初始化脚本,可以在服务器系统安装完毕之后立即执行.脚本结合各位大牛一些参数,已经在CentOS 5下通过. 使用方法:将其复制,保存为一个shell文件,比如init.sh ...
- 【bzoj2141】排队 [国家集训队2011]排队(树套树)
题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和. 红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别 ...
- ACM-ICPC 2016 大连赛区现场赛 K. Guess the number && HDU 5981(思维+DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5981 题意:A在[L, R]之间随机选取一个数X,之后B来猜这个数,如果猜的数比X小,那么A就告诉B猜 ...