zoukankan      html  css  js  c++  java
  • 牛客练习赛78 C.CCA的子树(树形DP)

    题目链接

    做法:题目要求选出两个节点,满足任意一个不是另一个的祖先节点,最大化以两个节点为根的子树的点权和。
    满足任意一个不是另一个的祖先节点说明对于一个节点u来说,这两个节点必须是u的子孙节点,且处于不同的子树,我们可以在dfs的时候,传递上来更新,同时,必须是至少两个,我们可以把遍历子树的操作看成一个简单的循环,只有当大于等于第二次循环的时候,才更新答案。我们用一个(mx[u])表示以u为根的子树中,最大的子树和。

    这道题和很多统计子树的题目很像,考虑了子树对子树间的影响。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N = 200005;
    const ll inf = 1e18;
    ll ans = -inf;
    int h[N], e[N * 2], ne[N * 2], idx;
    void add(int a, int b)
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    int w[N], n;
    ll mx[N];
    
    ll dfs(int u, int fa)
    {
        ll sum = w[u];
        mx[u] = -inf;
        for(int i = h[u]; i != -1; i = ne[i])
        {
            int j = e[i];
            if(j == fa) continue;
            sum += dfs(j, u);
            //有多余两棵子树,才更新ans
            if(mx[u] != -inf) ans = max(ans, mx[u] + mx[j]);
            mx[u] = max(mx[u], mx[j]);
        }
        mx[u] = max(mx[u], sum);
        return sum;
    }
    
    int main()
    {
        memset(h, -1, sizeof h);
        //int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", &w[i]);
        
        int u, v;
        for(int i = 1; i < n; ++i)
        {
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        
        dfs(1, 0);
        
        if(ans == -inf) printf("Error");
        else printf("%lld
    ", ans);
        
        return 0;
    }
    
  • 相关阅读:
    HTML自学之旅(九)框架
    暑期逛世博 品文化新上海
    重构实践者手记(20130517)
    网页信息抓取DEMO
    正则表达式30分钟入门教程
    变量命名网站
    Thinkpad笔记本电脑进入BIOS不能选择UEFI/Legacy Boot选项
    Useful Expressions Business Correspondence
    DotNetNuke升级中遇到的问题
    DNN端口的问题
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/14527425.html
Copyright © 2011-2022 走看看