P2986 [USACO10MAR] Great Cow Gathering 题解
true
Great Cow Gathering
USACO 2010 March Gold
提高+ /省选-
#3498db
- Luogu P2986
简述一下题目:
题目给定了一张带有边权的树,要求我们对于每一个点 $u$ 求出 $\displaystyle \sum_{v \in S} c_v \times \operatorname{dis}(u,v)$,并输出所有点的答案中的最小值。
首先我们可以很简单地通过一次DFS求出来树根的答案,就是 $\displaystyle \sum_{v \in S} c_v \times \operatorname{dis}(1,v)$。
对于每一个节点,我们记录两个信息:该节点的答案ans
和其子树内的 $c_i$ 之和sum
。
当我们DFS回溯到该节点 $u$ 的时候,我们的答案就是 $\displaystyle \sum_{v \in {\text{son of} u}} \operatorname{ans}(v) + \operatorname{sum}(v) \times \operatorname{dis}(u,v)$。
为了不与最终的答案冲突,这里将初步的答案命名成了dis
。
1 | ll sum[N], dis[N]; |
然后考虑怎么转移到其他节点。
这里就可以使用换根DP来求解了。
考虑我们从一个节点转移到其的一个子节点。
当前我们已经求出了当前这个节点的答案,此时我们所有的奶牛已经到达了当前的节点。
我们转移到其子节点的时候,可以等价成把所有的奶牛移动到这个子节点。
那么在该子节点子树中的所有奶牛都少走了 $(u,v)$ 这个边,而剩下的所有奶牛都多走了这一条边。
那么我们第二遍DFS的代码如下:
1 | void dfs2(int p, int fa) |
然后我们的答案就出来了,求个最小值输出即可。
完整代码如下:
1 |
|