cf1330 E. Drazil Likes Heap(贪心)
https://codeforces.com/contest/1330/problem/E
题意:
有一个高度为 \(h\) 的满大根堆,也就是有 \(2^h-1\) 个结点的满二叉树,父结点的值总大于两个子结点的值。结点的值两两不同,且从上到下、从左到右编号为 \(1\sim 2^h-1\) 。定义一种 “删除” 操作:
如果结点 \(i\) 没有儿子,删除 \(i\) ,即令 \(a[i] = 0\);否则,递归删除值较大的儿子。
现要删去 \(2^h-2^g\) 个结点,使其变成高度为 \(g\) ,结点数为 \(2^g-1\) 的满二叉树。输出一种删点方案,使新树的所有结点值之和最小。
思路:
删除实际上是找一条连接 \(i\)、\(i\) 的大儿子、大儿子的大儿子…… 的链,把这条链整体上移一位,链的末尾位置置0,也就相当于删去链的末尾。从小到大遍历编号,如果从 \(i\) 开始的链的末尾位置的编号(用\(get\_id\)函数求出)超过了新树的范围就一直删
#include
using namespace std;
#define ls(x) (x<<1)
#define rs(x) ((x<<1)|1)
const int N = (1<<21)+10;
int ans[N], a[N]; //树
void del(int i)
{
if(!a[ls(i)] && !a[rs(i)])
a[i] = 0;
else if(a[ls(i)] > a[rs(i)])
a[i] = a[ls(i)], del(ls(i));
else
a[i] = a[rs(i)], del(rs(i));
}
int get_id(int i)
{
if(!a[ls(i)] && !a[rs(i)])
return i;
if(a[ls(i)] > a[rs(i)])
return get_id(ls(i));
else
return get_id(rs(i));
}
signed main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T; cin >> T; while(T--)
{
int h, g; cin >> h >> g;
//注意初始化,要把后面的点置0
fill(a+(1<> a[i];
int cnt = 0;
for(int i = 1; cnt < (1< (1<