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
*/

原文地址:https://www.cnblogs.com/heyuhhh/p/10398307.html

时间: 2024-11-09 15:53:52

Codeforces Round #530 (Div. 2):D. Sum in the tree (题解)的相关文章

Codeforces Round #417 (Div. 2) E. Sagheer and Apple Tree(树上Nim)

题目链接:Codeforces Round #417 (Div. 2) E. Sagheer and Apple Tree 题意: 给你一棵树,每个节点有a[i]个苹果,有两个人要在这个树上玩游戏. 两个人轮流操作,谁不能操作谁就输了. 这个树有一个特性:叶子到根的距离的奇偶性相同. 每次操作可以选一个节点i,和一个数x,x小于当前节点i的苹果数. 对于节点i,如果是叶子节点,就将这x个苹果吃掉. 如果是非叶子节点,就将这x个苹果移向节点i的任意儿子节点. 现在第二个操作的人要交换两个节点的苹果

Codeforces 1099 D. Sum in the tree-构造最小点权和有根树 贪心+DFS(Codeforces Round #530 (Div. 2))

D. Sum in the tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Mitya has a rooted tree with nn vertices indexed from 11 to nn, where the root has index 11. Each vertex vv initially had

Codeforces Round #530 (Div. 1)

A - Sum in the tree 就是贪心选尽量让上面的点权尽量大,那么对于偶数层的点,其到根节点的和即为所有儿子中的最大值. #include<bits/stdc++.h> using namespace std; char gc() { // static char buf[100000],*p1,*p2; // return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin))?EOF:*p1++; return get

Codeforces Round #530 (Div. 2)

RANK :2252 题数 :3 补题: D - Sum in the tree 思路:贪心 把权值放在祖先节点上 ,预处理 每个节点保存 他与他儿子中 权值最小值即可. 最后会有一些叶子节点依旧为 INF 权值按0算即可,然后其他的权值计算为 它 - 它父亲的. 注意判断时候会出现父亲比儿子大的这种非法情况. #include<bits/stdc++.h> using namespace std; #define inf 0x7f7f7f7f #define ll long long #de

Codeforces Round #530 (Div. 2) E (树形dp+线段树)

链接: 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干需要花费bi时间,有两个玩家,玩家一可以移动到当前点的子节点也可以申请游戏结束返回根节点并吃沿途的饼干,玩家二可以删除当前点到儿子节点的一条边,走路和吃饼干都消耗时间,会给出一个总时间,在总时间内尽可能的多吃饼干,问最多能吃多少个? 思路: 由于是玩家一先手,那么最开始的最大边则不会被删除,但之后路途的最大边都会被玩家二删除,所以我们对于当前点我们需要求: 1.如果现在回头那么最多可以吃到多少饼干 2.向下

Codeforces Round #530 (Div. 2)F Cookies (树形dp+线段树)

题:https://codeforces.com/contest/1099/problem/F 题意:给定一个树,每个节点有俩个信息x和t,分别表示这个节点上的饼干个数和先手吃掉这个节点上一个饼干的的时间.然后有先手和后手俩个人. ?先手可以这么操作:在规定总时间T到达某个节点然后一定要返回根节点1,期间可以选择吃掉某些节点上的某些饼干(前提是保证剩下的时间能够回到根节点): ?后手可以这么操作:在先手到达的位置和这个位置的孩子之间的连边选择一条让先手吃得更多的边摧毁掉,也可以跳过这个过程: 问

Codeforces Round #530 (Div. 2) (前三题题解)

总评 今天是个上分的好日子,可惜12:30修仙场并没有打... A. Snowball(小模拟) 我上来还以为直接能O(1)算出来没想到还能小于等于0的时候变成0,那么只能小模拟了.从最高的地方进行高度的模拟,如果遇到石头就去判断一下会不会小于0其他没有什么好说的了 代码 #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int

Codeforces 1099 B. Squares and Segments-思维(Codeforces Round #530 (Div. 2))

B. Squares and Segments time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Little Sofia is in fourth grade. Today in the geometry lesson she learned about segments and squares. On the way home

Educational Codeforces Round #54 (Div. 2) E. Vasya and a Tree 技巧題

題目連接:http://codeforces.com/contest/1076/problem/E 本題大意: 給一棵根節點為"1"樹,給m個操作,每個操作三個整數,v,d,x,意思是從節點1,往下深度d,遍及的節點的值都加上x,d可能是0,就是只加在自己上.結束m個操作后輸出每個節點的值. 解題思路: 這裡不應該考慮同時操作整棵樹.因為每個節點的子樹是多樣的,而應該以dfs的形式,直接搜到葉子節點,這樣沿途就是一條鏈.每時每刻都在操作一條鏈,也就是一段區間.這樣操作轉化為:一個節點往