luoguP1090ybtoj堆例题1合并果子
Posted SSL_ZZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP1090ybtoj堆例题1合并果子相关的知识,希望对你有一定的参考价值。
Link
luogu传送门
ybtoj传送门
题面
//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了
题目大意
一个序列,每两个数字可以加在一起,消耗能量为这两个数字的和,将序列最后+为一个数字,且能量消耗最少
//xs,和原题长得一点都不像,又好似一模一样
解题思路
堆
堆的基本背景
堆就是树,且是完全二叉树
小根堆,父亲必须比儿子小,这就使得根节点一定是最小的那个
大根堆,父亲必须比儿子大,根节点一定是最大的那个
复杂度:取最大/最小
O
(
1
)
O(1)
O(1),维护堆
O
(
l
g
n
)
O(lg\\ n)
O(lg n)
堆的常用操作
以下以小根堆为例
- 建树:就是将堆初始化处理,每加一个数就用up()维护 //反正我是这么建树的
- up():与自己的父亲比较,如果比父亲小,也就是应该在上面,就和父亲交换,不断up()上浮
- down():与两个儿子比较,如果应该待在下面,就和儿子交换,不断下沉
- 删堆头:将堆头替为堆最后的数,删掉最后一个数,然后down()维护 //这样替保证树中间不会有空(完全二叉树)
堆的大板子题
//没想到有一天还要打这题,真是使不得,而且我还没打过这个板子博客:(
由小学知识可得,越小的数加在一起能量消耗的越少,如果不停sort()一定会爆
小根堆取最小数,复杂度大约
O
(
n
l
g
n
)
O(nlg\\ n)
O(nlg n)
Code
#include <iostream>
#include <cstdio>
using namespace std;
int n, k;
long long ans, a[40100];
void up(int x) {
while(x > 1 && a[x / 2] > a[x]) { //和父亲比较
a[0] = a[x], a[x] = a[x / 2], a[x / 2] = a[0];
x = x / 2;
}
}
void down(int x) {
int t = x * 2;
if (t < n && a[t] > a[t + 1]) t++; //更小的儿子会更有可能交换
while(x <= n && t <= n && a[x] > a[t]) {
a[0] = a[x], a[x] = a[t], a[t] = a[0];
x = t, t = x * 2;
if (t < n && a[t] > a[t + 1]) t++;
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
up(i); //建树
}
for(int i = 1, m = n; i < m; i++) {
k = a[1], a[1] = a[n], n--, down(1); //把第一个数提出来,并删堆头
a[1] += k, ans += a[1], down(1); //将第二数变为两个最小数的和,down()维护
}
printf("%lld", ans);
}
以上是关于luoguP1090ybtoj堆例题1合并果子的主要内容,如果未能解决你的问题,请参考以下文章