[CF1329C] Drazil Likes Heap - 贪心
Description
定义一种堆的删除操作:对节点x操作,相当于从x出发,每次向大儿子走,直到走到叶子节点,删掉叶子节点,把路径上(除x外)每个值都向上移一步,最后把x原本的值覆盖掉。将大顶堆从高度h降低到g,必须应用题中的算法保证它们的和最小,输出和,并且输出被删除操作的序号。
Solution
不断对根节点执行算法删除操作,如果根不能删了(再删就会导致 g 层有空位)就递归处理左右子树
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5000005;
int h, g, a[N];
vector<int> ans, res;
void del(int p)
{
if (a[p * 2] == 0 && a[p * 2 + 1] == 0)
{
a[p] = 0;
return;
}
if (a[p * 2] < a[p * 2 + 1])
{
a[p] = a[p * 2 + 1];
del(p * 2 + 1);
}
else
{
a[p] = a[p * 2];
del(p * 2);
}
}
int get_leaf(int p)
{
if (a[p * 2] == 0 && a[p * 2 + 1] == 0)
{
return p;
}
if (a[p * 2] < a[p * 2 + 1])
{
return get_leaf(p * 2 + 1);
}
else
{
return get_leaf(p * 2);
}
}
void divide(int p)
{
if (!p)
return;
if (p >= (1 << g))
return;
while (get_leaf(p) >= (1 << g))
{
ans.push_back(p);
res.push_back(a[p]);
del(p);
}
divide(p * 2);
divide(p * 2 + 1);
}
void solve()
{
cin >> h >> g;
int n = (1 << h) - 1;
for (int i = 1; i <= 4 * n; i++)
a[i] = 0;
for (int i = 1; i <= n; i++)
cin >> a[i];
int sum = 0;
for (int i = 1; i <= n; i++)
sum += a[i];
divide(1);
for (auto i : res)
sum -= i;
cout << sum << endl;
for (auto i : ans)
cout << i << " ";
cout << endl;
ans.clear();
res.clear();
}
signed main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
solve();
}
}