1 条题解
-
0
自动搬运
来自洛谷,原作者为

一扶苏一
休息结束。邮箱 yifusuyi@qq.com搬运于
2025-08-24 22:11:39,当前版本为作者最后更新于2019-08-25 19:16:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
B [yLOI2019] 梅深不见冬
Background
风,吹起梅岭的深冬;霜,如惊涛一样汹涌;雪,飘落后把所有烧成空,
像这场,捕捉不到的梦。
醒来时已是多年之久,宫门铜环才长了铁锈,
也开始生出离愁。
——银临《梅深不见冬》
Description
给定一棵 个节点的树,在树上行走,每次要么选择一个没有到达过的子节点,要么返回父节点。想要在一个节点 放上梅花当且仅当 的任意子节点 都被放上了 朵梅花。在任意时刻可以收回任意节点的梅花。对于每个节点,求如果想在这个节点放梅花,则至少需要准备多少梅花。
Limitations

特殊性质1:每个节点的孩子结点个数不超过
特殊性质2:每个节点的孩子节点个数不超过
特殊性质3:任意一个节点到根的路径上的点数不超过 ,也即树高不超过
对于 的数据,保证
Solution
测试点 :
只有一个节点,输出 即可。期望得分
测试点 :
爆搜一个行走的顺序,然后可以 判断是否合法。时间复杂度 ,期望得分
测试点 :
注意到题目所规定的走法相当于按照树的某个dfs序走,即离开某个节点时必须遍历完它的子树,否则子树中一旦有一个节点没有被遍历到,则永远无法返回这个节点。
如果设在点 上放上 朵梅花最少需要 朵梅花的话,考虑对于 的两个孩子 ,如果先走 ,那么首先需要准备 朵梅花,放上了 朵梅花,剩余了 朵花,再走 ,需要准备 朵花,当前有 ,则需要额外准备 朵花。先走 的情况类似,比较一下哪种情况更优即可。
时间复杂度 ,期望得分
测试点 :
孩子节点个数不超过 ,于是爆搜一下走哪个孩子的顺序,用类似子任务 的方法统计,然后取最优的即可。
时间复杂度 ,其中 为最大的节点孩子个数。期望得分
测试点 :
树高不超过 ,考虑第 层的节点,答案显然是他们自身的权值,第二层的节点,答案是第三层的权值和。
对于第一层的根节点 ,考虑放满他的孩子的花费和在这个节点上放梅花的花费的关系:
如果放满它的孩子花费为 ,它的孩子的权值和为 ,则会剩余 朵梅花,由于 是个常量, 与 正相关。考虑当 时,需要额外花费 元,花费为 元,当 时,花费 元。由此可以发现,当 减小时,所需要的花费不会增大。又因为 与 正相关,因此放满它的孩子的花费变低,在这个节点上放梅花的花费不会增加。因此最小化放满它孩子的花费即可得到答案。
对于一个节点 ,设往这个节点上放上梅花至少需要准备 朵梅花,而 的权值为 ,我们的问题是选择一个最优的放梅花的序列,使得最终需要准备的梅花最小。这个问题的答案是按照 的不升序排序即可。
考虑证明这个结论:
设有两个节点 ,设 且 。
考虑先放 再放 需要准备的梅花朵数是 (一式),同理先放 所需要准备的梅花朵数是 (二式)。
由于 ,得 。 同理。对一式二式分别提出 。
则
$$\text{一式} = \max(ans_i, ans_j + w_i) = \max(a_i + w_i, ans_j + w_i) = w_i + \max(a_i, ans_j) $$$$\text{二式} = \max(ans_j,ans_i + w_j) = w_j + \max(a_j, ans_i) = w_j + \max(a_j, a_i + w_i) = w_j + a_i + w_i $$考虑一式的 如果取 ,那么 $\text{一式} = w_i + a_i < w_i + a_i + w_j = \text{二式}$
如果取 ,那么 $\text{一式} = w_i + w_j + a_j < w_i + w_j + a_i = \text{二式}$
因此,一式恒小于二式,先放 更优。
据此做数学归纳可得,按照 的不升序排序后的序列是最优的。
于是即可排序以后用上面的方式统计答案,时间复杂度 ,期望得分
测试点 :
发现上面的结论可以应用于这棵树上的任何一个节点,于是每个节点都按照这样的方法排序即可。时间复杂度 ,期望得分 。
Code
#include <cstdio> #include <vector> #include <algorithm> const int maxn = 100010; int n; int MU[maxn], ans[maxn]; std::vector<int>son[maxn]; void dfs(const int u); bool cmp(const int &_a, const int &_b); int main() { scanf("%d", &n); for (int i = 2, x; i <= n; ++i) { scanf("%d", &x); son[x].push_back(i); } for (int i = 1; i <= n; ++i) { scanf("%d", MU + i); } dfs(1); for (int i = 1; i < n; ++i) { printf("%d ", ans[i]); } printf("%d\n", ans[n]); return 0; } void dfs(const int u) { for (auto v : son[u]) { dfs(v); } std::sort(son[u].begin(), son[u].end(), cmp); int _ret = 0; for (auto v : son[u]) { if (_ret >= ans[v]) { _ret -= MU[v]; } else { ans[u] += ans[v] - _ret; _ret = ans[v] - MU[v]; } } ans[u] += std::max(0, MU[u] - _ret); } inline bool cmp(const int &_a, const int &_b) { return (ans[_a] - MU[_a]) > (ans[_b] - MU[_b]); }
- 1
信息
- ID
- 4501
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者