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 左偏树

安利 Jelly_Goat 神仙的blog

什么是左偏树呢?

就是一个类似二叉堆的东西,画出来像一个二叉树

前置芝士:

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 【模板】堆 (内含左偏树实现)的更多相关文章

  1. P3377 【模板】左偏树(可并堆) 左偏树浅谈

    因为也是昨天刚接触左偏树,从头理解,如有不慎之处,跪请指教. 左偏树: 什 么是(fzy说)左偏树啊? 前置知识: 左偏树中dist:表示到右叶点(就是一直往右下找,最后一个)的距离,特别的,无右节点 ...

  2. 洛谷 - P3377 - 【模板】左偏树(可并堆) - 左偏树 - 并查集

    https://www.luogu.org/problemnew/show/P3377 左偏树+并查集 左偏树维护两个可合并的堆,并查集维护两个堆元素合并后可以找到正确的树根. 关键点在于删除一个堆的 ...

  3. 【BZOJ-1455】罗马游戏 可并堆 (左偏树)

    1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1355  Solved: 561[Submit][Status][Discuss] ...

  4. zoj2334 Monkey King , 并查集,可并堆,左偏树

    提交地址:点击打开链接 题意:  N(N<=10^5)仅仅猴子,初始每仅仅猴子为自己猴群的猴王.每仅仅猴子有一个初始的力量值.这些猴子会有M次会面. 每次两仅仅猴子x,y会面,若x,y属于同一个 ...

  5. [APIO2012]派遣 可并堆(左偏树)

    没啥说的,自底向上合并大根堆即可. 一边合并,一边贪心弹堆顶直到堆的总和不大于预算. Code: #include <cstdio> #include <algorithm> ...

  6. HDU3031 To Be Or Not To Be 左偏树 可并堆

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - HDU3031 题意概括 喜羊羊和灰太狼要比赛. 有R次比赛. 对于每次比赛,首先输入n,m,n表示喜羊羊和灰 ...

  7. 【bzoj2809】派遣 (左偏树)

    传送门 题目分析 每个节点都是一颗(大根堆)左偏树,先按bfs序存入数组,然后倒着从底层开始:如果当前节点的子树sum > m 那么就把根节点删去,然后统计更新答案,并将这棵树和父节点合并. c ...

  8. 洛谷 P3377 【模板】左偏树(可并堆)

    洛谷 P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或 ...

  9. [Luogu3377]【模板】左偏树(可并堆)

    题面戳我 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数 ...

随机推荐

  1. wpf win10 popup位置偏移问题

    同样问题参照: https://stackoverflow.com/questions/18113597/wpf-handedness-with-popups 解决方案: private static ...

  2. C++ STL 之 stack

    stack 是一种先进后出(first in last out,FILO)的数据结构,它只有一个出口,stack 只允许在栈顶新增元素,移除元素,获得顶端元素,但是除了顶端之外,其他地方不允许存取 元 ...

  3. 17.SpringMVC核心技术-拦截器

    SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定 的用户请求, 并进行相应的预处理与后处理.其拦截的时间点在“处理器映射器根据用户提 交的请求映射 ...

  4. Delphi 构造和析构

  5. axios 用 params/data 发送参数给 springboot controller,如何才能正确获取

    今天有人遇到接口调用不通的情况,粗略看了一下是axios跨域请求引起了.找到问题,处理就简单多了. 但是我看其代码,发现比较有意思 export function agentlist(query) { ...

  6. python+Appium自动化:toast定位

    Toast简介 Toast是一种简易的消息提示框. 当视图显示给用户,在应用程序中显示为浮动.和Dialog不一样的是,它永远不会获得焦点,无法被点击. 用户将可能是在中间键入别的东西.Toast类的 ...

  7. Thread setUncaughtExceptionHandler

    setUncaughtExceptionHandler 用于获取线程运行时异常 线程在执行时是不能抛出 checked 异常的,IDE 只会提示你用 try-catch 包裹起来.因此主线程无法直接获 ...

  8. Java 正则表达式获取两个字符中间的内容

    利用 正则表达式 获取两个字符串中间的值 直接上代码吧,不是很难. public static void main(String[] args) { // 内容 String value = &quo ...

  9. CAP理论概述

    CAP理论 CAP原则,指在一个分布式系统中,Consistency(一致性).Availability(可用性).Partitiontolerance(分区容错性),三者不可同时拥有. 一致性(C) ...

  10. struts2之单文件上传(7)

    前台页面jsp <!-- 拦截的时候用这个 <s:form action="uploadAction" enctype="multipart/form-dat ...