zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    C语言中const关键字的用法
    LDO和DC-DC的概念,区别及优缺点
    Ubuntu下几个命令行方式使用的图片浏览工具
    I2C和I2S的区别和使用方法
    scikit-image 图像处理库介绍
    USB协议介绍
    Ubuntu 16.04 python和OpenCV安装
    一种基于python的人脸识别开源系统
    numpy 介绍
    python enumerate用法总结
  • 原文地址:https://www.cnblogs.com/hanruyun/p/10239624.html
Copyright © 2011-2022 走看看