Codeforces 468D Tree

题目

给出一棵带边权的树,求一个排列\(p\),使得\(\sum_{i=1}^{n}{dis(i, p_i)}\)的值最大,其中\(dis(v, u)\)表示\(v\)到\(u\)的距离。

算法

这题的思路非常巧妙,又是和重心有关的题目!记得ydc的大树这题的ydc的做法有异曲同工之妙。

首先我们列答案的计算公式:\[\sum_{i=1}^{n}{dep_i+dep_{p_i}-dep_{lca(i,p_i)}}\]
其中\(dep(i)\)是\(i\)到根的距离,\(lca(v,u)\)就不用说了吧。
上面的式子等价于\[2 \sum_{i=1}^{n}{p_i}-\sum_{i=1}^{n}{dep_{lca(i,p_i)}}\]
我们就要使\(\sum_{i=1}^{n}{dep_{lca(i,p_i)}}\)最小化。

找到树的重心\(root\),并使它 变为根,显然我们有一种方法,使得\(lca(i,p_i)\)都是\(root\),所以答案就是\(2 \sum_{i=1}^{n}{p_i}\)。

难点在求字典序最小的排列\(p\)。

我们可以按\(1\)到\(n\)的顺序依次确定\(p_i\),根据贪心,我们每次必然选标号最小的点\(j\)。而且这个点要满足:

  • \(lca(i,j)=root\),我们可以把\(root\)去掉,那么一棵树就裂成了若干“小树”,那么就是要满足\(i\)和\(j\)不在同一个小树。
  • 仅仅满足上面的条件是不够的,因为有可能出现\(i\)和\(j\)只能在同一个小树的情况,所以我们要稍加限制:如果某个小树里出现了标号大于i的结点数量+还没有被选的结点数量=\(n-i\),那么,\(i\)或\(j\)之一 一定要在这个小树里。

我的代码

上一篇:MVC5 Entity Framework学习之Entity Framework高级功能


下一篇:亲身实践 yui-compressor压缩js和css