Xuan104_WA
2024-11-15 23:15:02
upd:修正了文中的一处错误。
动规妙妙题,代码完成于赛后一分钟内,诶诶。
给你一颗有根树,现要生成一颗满二叉树,使得对该二叉树经过若干次删点操作后可以使两棵树同构。
删点操作定义为:选择一个非根节点
求所需满二叉树高度的最小值,高度定义为根节点到叶子节点路径上的边数。
设
考虑转移,对于任意节点
每次选取所有儿子中二叉树高度最小的两个,设为
注意转移时要特判
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
int T,n,dp[1000005];
vector<int>G[1000005];
void dfs(int u){
if(G[u].size()==0)return;//叶子节点
for(int i=0;i<G[u].size();i++)dfs(G[u][i]);
if(G[u].size()==1){//特判只有一个儿子
dp[u]=dp[G[u][0]]+1;
return;
}
priority_queue<int>q;
for(int i=0;i<G[u].size();i++)q.push(-dp[G[u][i]]);//因为priority_queue默认大根堆,所以我们存负值以达到小根堆的效果
while(q.size()>1){
int x=q.top();q.pop();
int y=q.top();q.pop();
q.push(min(x,y)-1);//合并
}
dp[u]=-q.top();//记得符号要变回来
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)G[i].clear(),dp[i]=0;//多测要清空
int u;
for(int i=2;i<=n;i++){
cin>>u;
G[u].push_back(i);
}
dfs(1);
cout<<dp[1]<<endl;//输出根节点对应的值
}
return 0;
}