這是一題思維題,但我思維不好所以不會,來記錄一下
很明顯,對於每一個爲-1的結點,它的取值範圍只能爲[它的祖先,min(它的兒子)],如果不滿足這個必定輸出-1(每個結點都必須滿足這個,否則-1)。因爲我們要求的是sigema(ai),所以取值只能是兩個邊界,取中間的數必定會對答案造成貢獻(因爲我們計算ai的方式是s[i]-s[fa]),那我們應該取兩者的哪一個呢?答案是後者,如果取的是祖先的s,那麼這個結點最大的兒子的ai會非常大,爲了讓這個數更小,我們可以取最小的兒子的si。這樣雖然會讓這個結點的ai不爲0,但因爲si遞增,所以這樣做會令答案更優。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<list>
#define int long long
using namespace std;
list<int>lis[100005];
int fa[100005],s[100005],n,vis[100005];
int ans;
const int inf=0x3f3f3f3f;
void dfs1(int rt)
{
s[fa[rt]]=min(s[fa[rt]],s[rt]);//不能由最底一直推向最頂,否則不能判斷-1
vis[rt]=1;
for(list<int>::iterator it=lis[rt].begin();it!=lis[rt].end();it++)
{
if(!vis[*it])
dfs1(*it);
}
}
void dfs2(int rt)
{
vis[rt]=1;
if(s[rt]<s[fa[rt]]){
puts("-1");exit(0);
}
if(s[rt]!=inf)
ans+=s[rt]-s[fa[rt]];
for(list<int>::iterator it=lis[rt].begin();it!=lis[rt].end();it++)
{
if(!vis[*it])dfs2(*it);
}
}
signed main()
{
cin>>n;
for(int i=2;i<=n;i++)
{
scanf("%lld",&fa[i]);
lis[fa[i]].push_back(i);
lis[i].push_back(fa[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&s[i]);
if(s[i]==-1)s[i]=inf;
}
dfs1(1);
memset(vis,0,sizeof(vis));
/*for(int i=1;i<=n;i++)
{
cout<<s[i]<<endl;
}*/
dfs2(1);
cout<<ans;
}