【Codeforces Round #530】Sum in the tree(贪心构造)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}

猜你喜欢

转载自blog.csdn.net/Coldfresh/article/details/85994076