树的重心

· · 个人记录

树的重心

定义

树上一节点,且满足它的最大子树的节点数最小。

性质

$1.$ 删除重心后所得的所有子树,节点数不超过原树的 $\frac{1}{2}$,一棵树最多有 $2$ 个重心; 证明:这是树的重心的基本性质,如果重心的一个子树的节点数大于 $\frac{1}{2}$ 那么重心的这个子儿子肯定会比重心更有资格当重心,矛盾。 $2.$ 树中所有节点到重心的距离之和最小,如果有两个重心,那么他们距离之和相等; 证明:这种情况只有可能是 $2$ 个重心之间连边,并且重心 $1$ 的最大子树是以重心 $2$ 为儿子的子树,重心 $2$ 的最大子树也是以重心 $1$ 为儿子的子树。 $2$ 个子树大小相等,各为 $\frac{n}{2} 证明,这个可以用反证法。假设我们取极限情况。一个重心连的最大子树大小为 $\frac{n}{2}$,另一个大小为 $1$。因为如果新的重心不在 $2$ 个重心之间,它也会在最大的子树的儿子节点。那么此时这个儿子所连的子树总大小(除了返祖的子树)为 $\frac{n - 1}{2}$ 那么可以可以简单容斥一下推出返祖的子树大小为 $n + 1 - \frac{n - 1}{2}$ 也就是 $\frac{n + 3}{2}$ 大于 $\frac{n}{2}$ 所以矛盾。 $4.$ 树删除或添加一个叶子节点,重心最多只移动一条边; 证明:这个很简单,因为一个节点被修改最多只会改变一个子树的大小。所以重心最多只能移动一位。 ### 实现 首先是根据他的定义直接用 $Dfs$ 实现。 ``` int size[maxn], val[maxn], f[maxn];//size[i] 表示 i 的子树大小,val[i] 表示 i 节点的权值,f[i] 表示 i 为根节点的最大子树。 void Dfs(int x, int fa) { size[x] = val[x], f[x] = 0; Next(i, x) { int v = e[i].to; if(v == x) continue; Dfs(v, x); size[x] += size[v]; f[x] = max(f[x], size[v]); } f[x] = max(f[x], n - size[now]);//要考虑它父节点引出去的 if(f[x] < f[ans]) ans = x; } ```