CF1098A Sum in the tree(贪心)

满分做法:

由题:s[u]<=s[v](u是v的父亲),因为a[i]是非负的。此时点u和他儿子的点权和为:

\(s\left[ u \right] +\sum_{v\in son\left( u \right)}{(s\left[ v \right] -s\left[ u \right])}\)

\(=\left( 1-cnt\left( u \right) \right) *s\left[ u \right] +\sum_{v\in son\left( u \right)}{s}\left[ v \right]\)

\(k=\left( 1-cnt\left( u \right) \right) \le 0\)

所以\(s[u]\)越大点权和越小,最优的\(s[u]=min(s[v])\);对于s[i]为-1的点,我们先把他赋成较大的数,再通过他们的儿子对他进行赋值。而对于没有被更改的点(也就是偶数层的叶子结点),我们就令他为\(0\)保证答案最优.

#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
const int maxm=1e5+7;
int n;
ll ans;
int f[maxm];
ll s[maxm];
int main()
{
 scanf("%d",&n);
 for(int i=2;i<=n;i++)
 scanf("%d",&f[i]);
 for(int i=1;i<=n;i++)
 {
  scanf("%lld",&s[i]);
  if(s[i]==-1) s[i]=2147483647;
 }
 for(int i=2;i<=n;i++)
 s[f[i]]=min(s[i],s[f[i]]);
 for(int i=1;i<=n;i++)
 {
  if(s[i]<s[f[i]])
  {
   printf("-1\n");
   return 0;
  }
  if(s[i]<2147483647) ans+=s[i]-s[f[i]];
 }
 printf("%lld\n",ans);
 return 0;	
} 
posted @ 2019-10-17 14:29  lihan123  阅读(153)  评论(0编辑  收藏  举报