换根dp,CF 633F - The Chocolate Spree

一、题目

1、题目描述

2、输入输出

2.1输入
2.2输出

3、原题链接

633F - The Chocolate Spree


二、解题报告

1、思路分析

2600的题,但是不算很困难。

先考虑暴力做法,如何得到两条不相交的路径?

枚举删除的边,得到两棵子树,分别在两棵子树上进行dfs找最长路径

时间复杂度O(N^2)

考虑优化:换根dp

为什么能想到换根dp?

考虑答案可能"长什么样子":

1、两条路径分别在两个不相交子树中,此时,我们利用类似树的直径的求法,一次dfs就能搞定

答案就是两个 /\

2、两条路径在两棵相交子树中

这个时候答案长这个样子:

显然是由三段拼接而来的

对于根节点u,我们考虑固定子树v内的最长一段,然后考虑另外两段怎么选:

子树v1内的一段

子树v2内的一段

u向上的某段

从这三段中选两段

显然要维护根节点子树的最大值、次大值、次次大值

这个我们可以靠换根dp来进行维护

2、复杂度

时间复杂度: O(N)空间复杂度:O(N)

3、代码详解

复制代码
 ​
cpp 复制代码
#include <bits/stdc++.h>
using i64 = long long;
using i128 = __int128;
using PII = std::pair<int, int>;
const int inf = 1e9 + 7, P = 998244353;

struct Node {
    i64 fi, se, th, fiv, sev;  
};

void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    std::vector<std::vector<int>> g(n);
    for (int i = 0; i < n; i ++ ) std::cin >> a[i];
    for (int i = 1, u, v; i < n; i ++ ) {
        std::cin >> u >> v;
        -- u, -- v;
        g[u].push_back(v), g[v].push_back(u);
    }
    
    std::vector<i64> subAns(n);
    std::vector<Node> nodes(n);

    i64 res = 0;
    auto dfs1 = [&](auto&& self, int u, int fa) -> i64 {
        subAns[u] = a[u];
        i64 maxS = a[u], maxSubAnsV = 0;
        Node& p = nodes[u];
        for (int v : g[u]) {
            if (v == fa) continue;
            i64 s = self(self, v, u);
            res = std::max(res, maxSubAnsV + subAns[v]);
            maxSubAnsV = std::max(maxSubAnsV, subAns[v]);
            subAns[u] = std::max(subAns[u], maxS + s);
            maxS = std::max(maxS, s + a[u]);
            if (s > p.fi) {
                p.th = p.se, p.se = p.fi, p.fi = s;
                p.sev = p.fiv, p.fiv = v;
            }
            else if (s > p.se) {
                p.th = p.se, p.se = s;
                p.sev = v;
            }
            else if(s > p.th)
                p.th = s;
        }
        subAns[u] = std::max(subAns[u], maxSubAnsV);
        return maxS;
    };

    dfs1(dfs1, 0, -1);

    auto dfs2 = [&](auto&& self, int u, int fa, i64 maFa) -> void {
        Node& p = nodes[u];
        for (int v : g[u]) {
            if (v == fa) continue;
            if (v == p.fiv) {
                res = std::max(res, subAns[v] + a[u] + p.se + std::max(p.th, maFa));
                self(self, v, u, a[u] + std::max(p.se, maFa));
            }
            else {
                i64 s = p.se;
                if (v == p.sev) s = p.th;
                res = std::max(res, subAns[v] + a[u] + p.fi + std::max(s, maFa));
                self(self, v, u, a[u] + std::max(p.fi, maFa));
            }
        }
    };
    dfs2(dfs2, 0, -1, 0);
    std::cout << res;
}

int main(int argc, char** argv) {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    int _ = 1;
    // std::cin >> _;
    while (_ --)
        solve();
    return 0;
}
相关推荐
小码农<^_^>31 分钟前
优选算法精品课--滑动窗口算法(一)
算法
羊小猪~~33 分钟前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
软工菜鸡1 小时前
预训练语言模型BERT——PaddleNLP中的预训练模型
大数据·人工智能·深度学习·算法·语言模型·自然语言处理·bert
南宫生1 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
AI视觉网奇1 小时前
sklearn 安装使用笔记
人工智能·算法·sklearn
JingHongB2 小时前
代码随想录算法训练营Day55 | 图论理论基础、深度优先搜索理论基础、卡玛网 98.所有可达路径、797. 所有可能的路径、广度优先搜索理论基础
算法·深度优先·图论
weixin_432702262 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论
小冉在学习2 小时前
day52 图论章节刷题Part04(110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长 )
算法·深度优先·图论
Repeat7152 小时前
图论基础--孤岛系列
算法·深度优先·广度优先·图论基础
小冉在学习2 小时前
day53 图论章节刷题Part05(并查集理论基础、寻找存在的路径)
java·算法·图论