版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Coldfresh/article/details/85994076
做法: 我之前错误的做法是从前往后推的,优先最小,但是显然这是错误的,随便构造一个就能找到反例,当时没什么时间了,就没有怎么仔细想。因为实际上当越往根节点靠近时,这个点值应该越大越好,因为他可以以他为根子树的贡献越多,使得总体所有点权和越小,这个从直觉上就可以分析出来应该是没有问题,所以这个应该得从后往前推,如果这个点的s值没确定,那么应该取他的子节点的的s值当中的最小值。如果发现他的子节点都是-1,那么实际就不需要更新。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 100005
#define ll long long
#define INF 2000000000
using namespace std;
int n;
int head[maxn],to[maxn],_next[maxn],edge;
void addEdge(int x,int y)
{
to[++edge]=y,_next[edge]=head[x],head[x]=edge;
}
int s[maxn];
ll ans=0;
bool sign=true;
void dfs(int u)
{
int temp=INF;
for(int i=head[u];i;i=_next[i])
{
int v=to[i];
dfs(v);
if(!sign)return;
if(s[v]!=-1)temp=min(temp,s[v]);
}
if(s[u]==-1)
{
if(temp!=INF)
{
s[u]=temp;
for(int i=head[u];i;i=_next[i])
{
int v=to[i];
if(s[v]!=-1)ans+=s[v]-s[u];
}
}
}
else
{
if(s[u]>temp)
{
sign=false;
return;
}
for(int i=head[u];i;i=_next[i])
{
int v=to[i];
if(s[v]!=-1)ans+=s[v]-s[u];
}
}
}
int main()
{
cin>>n;
int x;
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
addEdge(x,i);
}
for(int i=1;i<=n;i++)scanf("%d",s+i);
dfs(1);
if(s[1]!=-1)ans+=s[1];
if(sign)cout<<ans<<endl;
else cout<<-1<<endl;
return 0;
}