Sum in the tree
题意:一颗n个个节点的树,有n-1条边,pi为i节点与pi节点相连,每个节点有个权值,但现在只知道根节点的权值和奇数层节点到根节点的所经过的点的权值之和,偶数层到根节点的和未知,标位-1,让你求出所有点的权值之和最小的值,不能求出,输出-1.
思路:通过样例我们可以发现当偶数层为它的子节点中的最小值的时候,结果是最小的,因为当该节点在小一点的时候它的所有子节点的值都要加上它小的那些值,而为偶数层的叶子节点我们直接赋值为零就行了,两遍dfs,第一遍把偶数层的s值求出来,第二遍把他们的实际权值求出来,注意有不合法情况,即该节点小于它的父亲节点的情况.

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+7;
struct node
{
int u,v;
int next;
}a[MAXN*2];
int cnt=1;
int head[MAXN];
int p;
long long s[MAXN];
void add(int u,int v)
{
a[cnt].u=u;
a[cnt].v=v;
a[cnt].next=head[u];
head[u]=cnt++;
}
bool vis[MAXN];
bool vis2[MAXN];
void dfs1(int cur,int fa)
{
for(int i=head[cur];i!=-1;i=a[i].next)
{
if(a[i].v==fa)
continue;
dfs1(a[i].v,cur);
if(s[a[i].v]!=-1&&vis[cur])
{
if(s[cur]==-1)
s[cur]=s[a[i].v];
else
s[cur]=min(s[cur],s[a[i].v]);
}
}
}
void dfs2(int cur,int fa)
{
for(int i=head[cur];i!=-1;i=a[i].next)
{
if(a[i].v==fa)
continue;
dfs2(a[i].v,cur);
if(vis2[a[i].v])
{
if(s[a[i].v]!=0)
s[a[i].v]-=s[cur];
}
else
s[a[i].v]-=s[cur];
}
}
int main()
{
int n;
memset(head,-1,sizeof(head));
memset(s,0,sizeof(s));
cnt=1;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
scanf("%d",&p);
add(p,i);
add(i,p);
}
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++)
{
scanf("%lld",&s[i]);
if(s[i]==-1)
vis[i]=true;
}
int temp=s[1];
dfs1(1,0);
s[1]=temp;
memset(vis2,false,sizeof(vis2));
for(int i=1;i<=n;i++)
{
if(s[i]==-1)
{
vis2[i]=true;
s[i]=0;
}
}
dfs2(1,0);
long long int ans=0;
bool flag=true;
for(int i=1;i<=n;i++)
{
if(s[i]<0)
{
flag=false;
break;
}
ans+=s[i];
}
if(flag)
printf("%lld\n",ans);
else
printf("-1\n");
return 0;
}

浙公网安备 33010602011771号