题目
如题,初始小根堆为空,我们需要支持以下3种操作:
操作1: 1 x 表示将x插入到堆中
操作2: 2 输出该小根堆内的最小数
操作3: 3 删除该小根堆内的最小数
二叉堆
支持两种操作
1.往一个集合加一个数。
2.从集合中删去一个优先值最大的元素。
规则
每个结点比儿子优先级大。
插入规则:先插入到最后一个结点,然后不停与父节点交换,直到到了根节点或者比父节点大。
删除根并返回规则:(只能删除根)先记录根、,然后把最后一个结点放到根的地方,然后不停地反方向交换,也就是将挪过来的结点与左右儿子比较,找到比较小的一个,与其交换,直到到了叶子结点或者比左右儿子都小。
复杂度分析
(1).层数:logn
(2).插入或删除:至多logn
单次操作:O(logn)
例题:合并果子 (原理是哈夫曼树)
每个果子的代价:重量*在树中深度
考虑这样构造出来的树,深度越深的结点权值越小,从而达到最小权值。
代码
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#define _for(i,a,b) for(int i = a; i<b; i++)
#define _rep(i,a,b) for(int i = a; i<=b; i++)
using namespace std;
const int maxn = 1000000+10;
int n, t[maxn], cc;
void add(int x){
t[++cc] = x; // 根节点用1表示,是为了方便表示没有结点0
int now = cc, fa = cc/2;
while(fa && x < t[fa]){
swap(t[now], t[fa]);
now = fa;
fa /= 2;
}
}
int out(){
printf("%d\n", t[1]);
}
void del(){
t[1] = t[cc];
cc--;
int now = 1, nxt = 2;
if (nxt < cc && t[nxt] > t[nxt+1]) nxt++;
while(nxt <= cc && t[now] > t[nxt]){
swap(t[now],t[nxt]);
now = nxt;
nxt *= 2;
if (nxt < cc && t[nxt] > t[nxt+1]) nxt++;
}
}
int main(){
scanf("%d",&n);
while(n--){
int a,x;
scanf("%d",&a);
if(a == 1){
scanf("%d",&x);
add(x);
} else if (a == 2){
out();
} else {
del();
}
}
return 0;
}