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. wireshark 分析过滤数据

    1.过滤IP,如来源IP或者目标IP等于某个IP例子:ip.src eq 192.168.1.107 or ip.dst eq 192.168.1.107或者ip.addr eq 192.168.1. ...

  2. WeakReference 与 SoftReference 区别

    装载自:http://flyneil.iteye.com/blog/1345177 WeakReference与SoftReference都可以用来保存对象的实例引用,这两个类与垃圾回收有关. Wea ...

  3. 【python】多进程、多线程、序列

    一.多进程 1.子进程永远返回0,而父进程返回子进程的ID.这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程 ...

  4. Cacti-0.8.8b详细安装及配置步骤

    1.  Cacti环境安装 1.1         安装LAMP环境 安装LAMP环境,当然,如果你有兴趣可以采用编译,我线上Mysql是编译的,其余是yum安装的.在这次实验采用yum安装. 关闭i ...

  5. python异步编程 (转载)

    Python Async/Await入门指南   转自:https://zhuanlan.zhihu.com/p/27258289 本文将会讲述Python 3.5之后出现的async/await的使 ...

  6. List、Set、Map 之间的区别是什么?(未完成)

    List.Set.Map 之间的区别是什么?(未完成)

  7. RxJava事件流变换者--操作符

    对于Rxjava来说,操作符是它的一个非常重要的概念,如官网: 而上节上也贴了一下都有哪些操作符,其实还不少,所以有必要仔细学习一下关于操作符这块的东东,那操作符在Rxjava中扮演着什么样的角色呢, ...

  8. 自定义ViewGroup基础巩固1---理解onLayout()方法

    自定义ViewGroup这个是在android中自定义控件中不可获缺的很重要的一部分,关于它的意义这里就不过多阐述了,为了在未来深入上继续走下去,所以先把基础给打牢. 这篇主要是理解ViewGroup ...

  9. thymeleaf小知识

    1.根据不同性别,显明不同的默认图片:th:if th:src   图片路径 <img th:if="${gender=='男'}" id="admission_p ...

  10. 前端小白页面开发注意事项及小工具(html\css\js)

    技术一直在向前发展.但是有一些是相通的,要找准重点,将80%的时间放在提升基础问题上,余下的20%再去学习框架,库和工具. HTML 1. HTML 属性应当按照以下给出的顺序依次排列,确保代码的易读 ...