1 条题解
-
0
D. Balanced Tree 题解
题目描述
给定一棵有 个节点的树,第 个节点有一个初始值范围 。你需要为每个节点选定初始值 。
你可以执行任意多次以下操作:
- 选择两个节点 ( 可与 相同),以 为整棵树的根,将 的子树中所有节点的值增加 。
目标是通过若干次操作,使所有节点的最终值相等(称为“平衡”),并求出平衡时的最小可能值。注意:只需最小化最终值,无需最小化操作次数。
数据范围
- 测试用例数
- 单用例节点数 ,所有用例
思路分析
操作的本质
若以任意节点为根,操作「以 为根,增加 的子树」等价于:我们可以独立地增加树中任意一个连通块的值。具体来说,对于任意一条边 ,我们既可以增加 一侧的连通块(以 为根,操作 的子树),也可以增加 一侧的连通块。
因此,当我们选定一组初始值 后,可以通过增加某些连通块来消除节点间的差值,最终达到一个全局值 。每条边两侧连通块的最大值差异,必须通过增加较小一侧来弥补,而这些弥补量将直接决定 的最小值。
贪心 DP 设计
考虑以节点 为根,自底向上进行 DP。对每个节点 ,定义 表示 在其子树范围内被调整到的值(不是最终全局值)。我们要求 满足 ,并且为了使全局值尽量小,应当让 尽可能大,以减少向父节点传递的差值。
令 为 的所有子节点 的最大值。显然 的值不能低于任意子节点的值(否则无法通过只增加另一侧来抹平差距),因此 。同时, 也不能低于 ,也不能高于 。综合得到:
对于每条边 ( 是 的子节点),若 ,那么为了平衡这一侧,我们必须将 所在的另一侧(或整棵树的其他部分)的值增加 ,这将直接贡献到最终全局值中。因此,答案累加 。
最终,根节点 没有父节点,其本身的值 也是全局值的基础组成部分,因此总答案为:
$$\text{ans} = a_0 + \sum_{u} \sum_{v \in \text{son}(u)} \max(0, a_v - a_u) $$算法步骤
- 读取 及每个节点的 。
- 建无向图,以 为根进行 DFS(通过删除反向边转为有根树)。
- 自底向上计算:
- 初始化
- 对每个子节点 :
- 递归计算
- 对每个子节点 ,累加 到答案
- 输出 。
时间复杂度 ,总复杂度 ,可以轻松通过。
代码实现
#include <bits/stdc++.h> using namespace std; #define all(x) (x).begin(),(x).end() int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T--) { int n; cin >> n; vector<int> l(n), r(n), a(n); for (int i = 0; i < n; ++i) cin >> l[i] >> r[i]; vector<vector<int>> e(n); for (int i = 1; i < n; ++i) { int u, v; cin >> u >> v; --u; --v; e[u].push_back(v); e[v].push_back(u); } long long ans = 0; function<void(int)> dfs = [&](int u) { int mx = l[u]; for (int v : e[u]) { // 删除反向边,防止重复访问父节点 auto it = find(all(e[v]), u); if (it != e[v].end()) e[v].erase(it); dfs(v); mx = max(mx, a[v]); } a[u] = min(mx, r[u]); for (int v : e[u]) ans += max(0, a[v] - a[u]); }; dfs(0); cout << ans + a[0] << '\n'; } return 0; }
样例说明
以题目第一个样例为例(已转化为 -indexed):
n = 4 l, r: 0: 0 11 1: 6 6 2: 0 0 3: 5 5 边: 1-0 (原2-1) 2-0 (原3-1) 3-2 (原4-3)以节点 为根,执行 DFS:
- 节点 (叶):,,。
- 节点 :,子节点 的 ,,,贡献 。
- 节点 (叶):,,,贡献 。
- 节点 :,子节点 和 ,,,贡献 。
累计贡献 ,最终答案 ,与样例输出一致。
总结
本题通过树上贪心 DP,利用操作可增加任意连通块的性质,自底向上合并子节点信息,并尽量让每个节点取到其允许范围内的最大值,从而最小化必要的全局提升量。代码简洁高效,适用于 的大规模数据。
- 1
信息
- ID
- 6607
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者