zoukankan      html  css  js  c++  java
  • Codeforces Round #530 (Div. 2):D. Sum in the tree (题解)

    D. Sum in the tree

    题目链接:https://codeforces.com/contest/1099/problem/D

    题意:

    给出一棵树,以及每个点的si,这里的si代表从i号结点到根节点的权值和。但是有些si=-1,这就相当于丢失了当前结点的数据。

    假设原本每个点的权值为ai,那么现在求sum{ai}的最小为多少,ai为非负数。

    题解:

    这题可以单独看每一条链上的s值,假设当前结点为u,儿子结点v,那么就有几种情况:

    1.su==-1&&sv==-1,这种不用管,继续往下看;

    2.su==-1&&sv>=0,这种情况,su以及上面可能有多个si为-1的结点,但这里我们可以就把它看作一个点,然后找到非-1父亲结点的s值,假设为p,那么sv-sp就是中间结点的权值和,看作一个点的话,就是那个点的a值,同时根据这个我们可以计算出其sum值。至于这里怎么求sp,可以在dfs的时候记录一下。

    3.su>=0&&sv==-1,这里就需要上面的记录了,记录目前的su值,方便后面找sp

    4.su>=0&&sv>=0,这里直接往下搜索就行了。

    结合上面的分析,我们只需要一个dfs记录一下就好了,最后求au的时候就是sumu-sump,也可以在dfs的过程中处理。

    但是我们刚才只是对链的分析,一个结点可能有多个儿子结点。想一下,会发现只有上面第2种情况会多考虑一点,因为根据哪个儿子结点来确定当前的s是一个问题。

    这个问题也不难解决,取min{sv-sp}即可,一方面是让其尽量大,另一方面是保证方案可行。

    最后再判断一下可行性就行了。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5+5;
    int n;
    vector <int> g[N];
    ll sum[N],b[N];
    int flag = 0;
    void dfs(int u,ll a,int fa){
        int son = 0;
        if(flag) return ;
        int f=0;
        for(auto v:g[u]){
            if(v==fa) continue ;
            if((sum[u]==-1 && sum[v]>=0) ||f){
                f=1;
                ll now=sum[v]-a;
                if(sum[u]==-1) sum[u]=now+a;
                if(sum[u]!=-1) sum[u]=min(sum[u],now+a);
            }
        }
        for(auto v:g[u]){
            if(v==fa) continue ;
            son++;
            if(sum[v]==-1 && sum[u]==-1){
                dfs(v,a,u);
                continue ;
            }
            dfs(v,sum[u],u);
        }
        if(son==0&&sum[u]==-1){
            b[u]=0;
            return ;
        }
        if(sum[u]!=-1) b[u]=sum[u]-a;
    }
    int main(){
        cin>>n;
        for(int i=2;i<=n;i++){
            int f;
            scanf("%d",&f);
            g[f].push_back(i);
            g[i].push_back(f);
        }
        for(int i=1;i<=n;i++) scanf("%I64d",&sum[i]);
        if(sum[1]==-1) sum[1]=0;
        dfs(1,0,-1);
        for(int i=1;i<=n;i++){
            if(b[i]<0) flag=1;
        }
        if(flag) puts("-1");
        else{
            ll ans = 0;
            for(int i=1;i<=n;i++) ans+=b[i];
            cout<<ans;
        }
        return 0;
    }
    /*
    7
    1
    2
    1
    4 4 5
    0 -1 3 -1 -1 3 -1
    */
  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10398307.html
Copyright © 2011-2022 走看看