每日一题:Accumulation Degree
题意
给定一棵n个节点的树,边权值视作流量,找到一个源点使得从该点出发到所有叶子节点流量和最大。
思路:
我们先考虑这样一道题:指定一点使得到树上其他点的深度之和最小。
这显然是树的重心的性质:树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个重心,他们的距离和一样。
我们先假设这棵树的根为1,进行一次dfs,可以求出每个点的深度 $dep[i]$ 和子树大小 $size[i]$ ,设某点作为根深度之和为 $f$( i ),显然:$f(1)$ = $\sum_{i=1}^{n}{dep[i]}$。
当根从 $u$ 转移到子节点 $v$ 时,以 $v$ 为根的子树内所有节点 $dep$ 都减1,其余节点加1。从而得到状态转移方程:$f[v] = f[u] - size[v] + (n - size[v]) = f[u] + n - 2 * size[v]$,答案取最小值即可,时间复杂度 $O (n)$ 。
Code
1 |
|
现在我们回过头来看这道题,可以发现思路都大同小异,只是转移方程发生了变化。
定义 $flow[i]表示以 i 为根的子树中流量的最大值$,那么,当节点从 $u$ 转移到 $v$ 时,我们可以得到:
- 当 $v$ 为叶子结点,则 $flow[u] += flow[v]$ ;
- 当 $u$ 为非叶子结点,则 $flow[u] = min(flow[v], fl(u, v))$ $(fl(u, v) 即u, v两点间的流量限制)$ 。
这样,根为1时的 $flow[1]$ 就求出来了。
接下来考虑根节点的转移:从以 $u$ 为根节点转移为以 $v$ 为根节点,对于根节点 $v$ 而言,唯一会产生影响的就是 $v$ 流向 $u$ 的路径,也就是对于换根后所有用到这条边的路径,都要加上这条流量的限制,则状态转移方程为:
- 当 $u$ 为叶子节点时,$f[v] += fl(u, v)$ ;
- 当 $v$ 为非叶子结点时,$f[v] += min(fl(u, v), flow[u] - min(flow[v], fl(u, v)))$ 。
进行两次dfs即可,时间复杂度 $O(n)$。
Code
1 |
|
总结
对于换根dp,一般有两个步骤:
- 默认1为根进行dfs预处理;
- 从1开始,进行根的转移,计算贡献变化。
对于dp而言,状态转移方程是最重要的,需要多思考,多刷题,才能累积经验,掌握要点。