换根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;
}
相关推荐
hongyucai11 分钟前
详解rlinf强化学习四步曲
人工智能·python·算法·架构
变量未定义~12 分钟前
ST表-龙骑士军团【算法赛】
数据结构·算法
小帽子_12331 分钟前
储能 SOC/SOH 精准估算技术:储能工况下算法优化与误差修正方案
算法
hhlongg37 分钟前
FFT分析
算法
水龙吟啸1 小时前
华为2026.6.17机考选择题+编程题【速刷敲黑板】
人工智能·深度学习·算法·华为
凌波粒1 小时前
LeetCode--53. 最大子序和(贪心算法)
算法·leetcode·贪心算法
Hesionberger1 小时前
快速求解完全平方数的最少数量
开发语言·数据结构·python·算法·leetcode·c#
c238561 小时前
《序列 DP:C++ 中的“最长”套路与编辑距离》
c++·算法·动态规划
aqiu1111111 小时前
【算法日记 19】LeetCode 1. 两数之和:梦开始的地方,哈希表的降维打击
算法·leetcode·职场和发展
CS创新实验室11 小时前
算法、齿轮与硅基大脑:数值计算发展简史
人工智能·算法·数值计算