CF530D sum in the tree

我是题面原题地址

很简单的一道贪心题

首先,先想想怎么判断是否合法

题目中说,a是自然数,那么子节点的s明显是不能比父节点大的,如果比父节点大,不合法!

所有深度为偶数的点的s被删除了,也只有深度为偶数的点被删除了,所以如果深度为奇数的点被删除了,或者有深度为偶数的点没有被删除,不合法!

所有不合法的情况我们已经判断完了,下面考虑如何使权值和最小

对于奇数层的点我们肯定是无法影响了,只有通过控制偶数层的点的权值才能影响总的权值和,而且只能影响自己和自己子节点的权值

我们从简单的入手,对于偶数层叶子结点,我们直接让它的(s)等于父节点的(s)即可,这样(a)(0),合法且最优

对于有一个子节点的偶数层节点,取值在([s_{fa},s_{son}])中任意取值,总的权值和都是不变的。

简单证明一下,就是(a_{son}=s_{son}-s_v,a_{v}=s_v-s_{fa},a_v+a_{son}=s_{son}-s_{fa}),而两个(s)都是已知的,所以这里的s爱取啥取啥,只要合法就行

那么对于子节点大于1的偶数层节点我们怎么处理呢,我们设子节点的权值不全相同

那么(a_v=s_v-s_{fa},sum a_{son}=sum (s_{son}-s_v))

总的和就是(sum(s_{son}-s_v)+s_v-s_{fa})

显然,当(s_v)越小时,这个式子的值也就越小,同时我们还要保证合法,所以(s_v)我们就取最小的(s_{son})

为了程序的简练,我们将三种情况合并,简述为

若存在子节点则为最小的(s_{son}),否则为(s_{fa})

由于数据范围不小,记得开long long

就是这么简单,下面上代码,由于讲的已经很清楚了,代码就不加注释了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#ifdef ONLINE_JUDGE
#define puts(o) puts("I AK IOI
")
#endif
#define ll long long
#define gc getchar
#define maxn 100005
using namespace std;

inline ll read(){
    ll a=0;int f=0;char p=gc();
    while(!isdigit(p)){f|=p=='-';p=gc();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    return f?-a:a;
}int n,ans;ll sum;

struct ahaha{
    int to,next;
}e[maxn];int tot,head[maxn];
inline void add(int u,int v){
    e[tot]={v,head[u]};head[u]=tot++;
}

int f[maxn],dep[maxn];ll s[maxn],s1[maxn];
void dfs(int u,int fa){
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(~s[v]){
            if((dep[v]&1)^1){ans=1;return;}
        }
        else{
            if(dep[v]&1){ans=1;return;}
            s[v]=(s1[v]==1000000001?s[u]:s1[v]);
        }
        if(s[v]<s[u]){ans=1;return;}
        sum+=s[v]-s[u];
        dfs(v,u);if(ans)return;
    }
}
ll dfs(int u){
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        dep[v]=dep[u]+1;
        s1[u]=min(s1[u],dfs(v));
    }
    return s[u];
}

int main(){memset(head,-1,sizeof head);
    n=read();dep[1]=1;
    for(int i=2;i<=n;++i)
        add(read(),i);
    for(int i=1;i<=n;++i){
        s[i]=read();
        s1[i]=1000000001;
    }
    sum+=s[1];dfs(1);dfs(1,-1);
    if(ans)
        puts("-1");
    else
        printf("%I64d
",sum);
    return 0;
}
原文地址:https://www.cnblogs.com/hanruyun/p/10239624.html