codeforces#1329C - Drazil Likes Heap
C - Drazil Likes Heap
题意:
给定一个高度为$h$的完全二叉树,也满足最大堆的性质,执行下面操作,得到一个高度为$g$的完全二叉树
求操作后的完全二叉树的最小权值和,和操作的$id$

分析:
看了题解写的
从下往上考虑,定义h树为还没操作的树,定义g树为操作结束的树,经过观察发现,g树的叶子一定是当前位置在h树的最小节点,g树的其它节点只需要满足两个条件,第一,比它在g树的两个儿子要大,第二,来自于h树中当前位置的子树,所以贪心策略是一直找满足条件的最小值
构造方法:找到那些需要删除的节点,然后根据编号从大到小删除它们,因为大编号的删除不影响小编号的位置
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (int i=(a);i<=(b);i++)
#define per(i,a,b) for (int i=(b);i>=(a);i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef long long ll;
typedef vector<int> VI;
typedef pair<int,int> PII;
ll mod=998244353 ;
const int maxn=(1<<20)+7;
vector<PII>ve[maxn];
ll sum;
int ans[maxn],a[maxn],book[maxn],g,h;
void dfs(int x){
if(x*2>(1<<h)-1){
ve[x].pb(mp(a[x],x));
return ;
}
dfs(x*2);
dfs(x*2+1);
int st=0,en=0;
while(st<SZ(ve[x*2])&&en<SZ(ve[x*2+1])){
if(ve[x*2][st]<ve[x*2+1][en])ve[x].pb(ve[x*2][st]),st++;
else ve[x].pb(ve[x*2+1][en]),en++;
}
while(st<SZ(ve[x*2]))ve[x].pb(ve[x*2][st]),st++;
while(en<SZ(ve[x*2+1]))ve[x].pb(ve[x*2+1][en]),en++;
ve[x*2].clear();
ve[x*2+1].clear();
ve[x].pb(mp(a[x],x));
if(x<=(1<<g)-1){
int v=max(ans[x*2],ans[x*2+1]);
//upper_bound(ve[x].begin(),ve[x].end(),mp(v,1e9));
PII zz=*upper_bound(ve[x].begin(),ve[x].end(),mp(v,(int)1e9));
ans[x]=zz.fi;
book[zz.se]=1;
sum+=ans[x];
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d",&h,&g);
rep(i,1,(1<<h)-1)scanf("%d",&a[i]);
dfs(1);
printf("%lld\n",sum);
int fla=0;
per(i,1,(1<<h)-1){
if(book[i]==0){
if(fla==0)printf("%d",i),fla=1;
else printf(" %d",i);
}else book[i]=0;
}
printf("\n");
rep(i,1,(1<<h)-1)ans[i]=0;
ve[1].clear();
sum=0;
}
return 0;
}

浙公网安备 33010602011771号