内容简介:给出一个高度为 h 的大根堆, 要求弹出其中若干个数后高度变为 g, 并且前后大根堆都是满二叉树. 问新的大根堆所有数之和的最小值, 并要给出一种弹出数的操作序列(节点序号). h, g ≤ 20. 堆的弹出过程见如下代码:
题意
给出一个高度为 h 的大根堆, 要求弹出其中若干个数后高度变为 g, 并且前后大根堆都是满二叉树. 问新的大根堆所有数之和的最小值, 并要给出一种弹出数的操作序列(节点序号). h, g ≤ 20. 堆的弹出过程见如下代码:
题解
考虑新堆的每个节点的可能最小结果: 如果是叶子节点, 那么最小是取它的子树中最小的数; 否则, 取子树中比两个儿子大的数中的最小值.
那么, 能否能得到这个每个节点都取到最小值的堆呢, 回答是肯定的. 我们在得知哪些数字会留下后, 是要把其他点弹出的. 弹出这些数后, 我们还需要考虑新堆是不是满二叉树. 按序号从小到大考虑每个节点, 会发现(这个过程不太好描述, 主要还是堆的性质)每个节点最后的结果一定是以它为根的子树中剩余数字的最大值(被祖先节点使用的话是要移除的), 既然每个节点都有数字, 这个堆自然是满二叉堆.
要得到新堆的每个节点的数字, 可以从下到上维护每个节点的子树的序列. 每次合并都是 O(len) (len为序列长度) 的, 总的时间复杂度为 O(nlogn). 要输出操作序列时, 可以从下往上弹出不需要的数字, 这样不会影响到祖先的结构.
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++)
#define dec(i, l, r) for (int i = l; i >= r; i--)
const int maxn = (1 << 20) + 5;
int t, h, g;
int val[maxn], nxt[maxn];
vector<int> sub[maxn];
inline vector<int> Merge(vector<int> v1, vector<int> v2, int id) {
int sz1 = v1.size(), sz2 = v2.size();
vector<int> r(sz1 + sz2 + 1);
for (int i = 0, j = 0; i + j < sz1 + sz2;) {
if (j == sz2 || i < sz1 && v1[i] < v2[j]) {
r[i + j] = v1[i];
i++;
} else {
r[i + j] = v2[j];
j++;
}
}
r[sz1 + sz2] = val[id];
return r;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> t;
while (t--) {
cin >> h >> g;
inc(i, 1, (1 << h) - 1) cin >> val[i];
inc(i, 1 << h - 1, (1 << h) - 1) sub[i] = vector<int>(1, val[i]);
dec(i, (1 << h - 1) - 1, 1) {
sub[i] = Merge(sub[i << 1], sub[i << 1 | 1], i);
}
set<int> s;
ll sum = 0;
inc(i, 1 << g - 1, (1 << g) - 1) {
nxt[i] = sub[i][0];
s.insert(nxt[i]);
sum += nxt[i];
}
dec(i, (1 << g - 1) - 1, 1) {
inc(j, 0, (int)sub[i].size() - 1) if (sub[i][j] > nxt[i << 1] &&
sub[i][j] > nxt[i << 1 | 1]) {
nxt[i] = sub[i][j];
s.insert(nxt[i]);
sum += nxt[i];
break;
}
}
cout << sum << "\n";
dec(i, (1 << h) - 1, 1) {
if (s.find(val[i]) == s.end()) cout << i << " ";
}
cout << "\n";
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算机组成(第 6 版)
Andrew S. Tanenbaum、Todd Austin / 刘卫东、宋佳兴 / 机械工业出版社 / 2014-8-19 / CNY 99.00
本书采用结构化方法来介绍计算机系统,书的内容完全建立在“计算机是由层次结构组成的,每层完成规定的功能”这一概念之上。作者对本版进行了彻底的更新,以反映当今最重要的计算机技术以及计算机组成和体系结构方面的最新进展。书中详细讨论了数字逻辑层、微体系结构层、指令系统层、操作系统层和汇编语言层,并涵盖了并行体系结构的内容,而且每一章结尾都配有丰富的习题。本书适合作为计算机专业本科生计算机组成与结构课程的教......一起来看看 《计算机组成(第 6 版)》 这本书的介绍吧!