题解:CF1997D Maximize the Root
ICU152_lowa_IS8 · · 题解
考虑类似贪心的做法。
对于每一个节点,若要使其节点能达到的值最大,则其子树中的节点中的最小值也一定要尽可能大。
定义
假设
如果
如果
为什么这里不是将子树的权值全部加起来求平均值?因为父节点增加
如果一个节点有多个子节点,显然取在多个算得结果中取最小值即可。
由于我们知道对于任意一个叶子节点
问题来了,就算知道了
答案十分显然,将根节点权值和剩余节点中的最小值相加即可。
至于如何进行对树的遍历,方法一抓一大把,本人用的是拓扑排序,正确性无误即可。
此处提醒:注意多测清空以及清空方式,本人赛时查了半个小时错愣是没看出来。
上代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int dis[1000005];
int p[1000005];
int a[1000005];
int in[1000005];
struct node{
int v,w,next;
}edge[1000005];
int num;
int head[1000005];
void add(int u,int v,int w){
edge[++num].next=head[u];
head[u]=num;
edge[num].w=w;
edge[num].v=v;
}
queue<int>q;
void tupo(){
while(!q.empty()){
int t=q.front();
q.pop();
if(t==1)continue;
for(int i=head[t];i;i=edge[i].next){
int v=edge[i].v;
if(dis[t]>=a[v]){
if(v==1){
dis[v]=min(dis[v],dis[t]);
}
else
dis[v]=min(dis[v],(dis[t]+a[v])/2);
}
else{
if(v==1){
dis[v]=min(dis[v],dis[t]);
}
else
dis[v]=min(dis[v],min(dis[t],a[v]));
}
in[v]--;
if(!in[v])q.push(v);
}
}
}
signed main(){
int t;
cin>>t;
while(t--){
while(!q.empty())q.pop();
num=0;
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
head[i]=0;
}
for(int i=1;i<=n;i++){
in[i]=0;
}
for(int i=1;i<=n;i++){
dis[i]=0x3f3f3f3f3f3f3f3f;
}
for(int i=2;i<=n;i++){
int p;
cin>>p;
add(i,p,0);
in[p]++;
}
for(int i=2;i<=n;i++){
if(in[i]==0){
q.push(i);
dis[i]=a[i];
}
}
tupo();
cout<<dis[1]+a[1]<<endl;
}
return 0;
}