树的重心
树的重心
本文介绍了树的重心及其性质、如何动态维护修改权值的带权重心、如何寻找断边再加边的带权重心。
无根树的重心定义为:
令 \(x\) 为树根,有 \(y\) 与 \(x\) 相邻,使得 \(y\) 的子树大小的最大值最小,这样的 \(x\) 即树的重心。
重心有 1 个 或 2 个,若有 2 个则这 2 个重心相邻。
性质
以重心为根,任意一个它的儿子的子树大小不超过 \(n/2\)。
树中所有点到一个点的距离和中,到重心的最小。
根据性质,我们可以得出:
如果有一条边 \((x,y)\),将这条边割开,若 \(x\) 的子树大小大于 \(y\) 的子树大小,则重心在子树 \(x\) 中,反之在 \(y\) 中,若相等,则 \(x,y\) 恰好是两个重心。
同时,若在树上添加一个叶子,则重心最多移动一条边。
求法
扫一遍树求子树大小,根据定义即可求。
假定一个根 \(rt\),则一个点的值即 \(\max(sz_{son_x},sz_{rt}-sz_x)\),这个值最小点就是重心。
应用
点分治:
由于重心的子树大小不超过一半,则可以把树按重心分开,再把分开的每个连通子树递归处理,最多分 \(O(\log n)\) 层。
则所有重心的子树大小和是 \(O(\log n)\) 的,我们在这些重心上可以方便地计算路径等信息。
带权重心
每个点有权值,将上面定义中的子树大小换为权值和即为带权重心的定义。
依旧有性质:
如果有一条边 \((x,y)\),将这条边割开,若 \(x\) 的子树大小大于 \(y\) 的子树大小,则重心在子树 \(x\) 中,反之在 \(y\) 中。
若相等则需依照 \(x,y\) 的权值判断重心,相等则都为重心,否则谁大谁为重心。
可看出:若点权都不相等,则重心唯一。
根据性质动态维护区间修改权值的带权重心 \(O(d\log ^2n)\)
我们上面的性质结合点分治的思想:
先求出点分治的那些重心,从整颗树的重心开始,考虑移动。
若有子树满足性质,显然最多一个子树满足性质,则移动到连通子树的重心(无权重心)。
若没有,则当前点就是带权重心。
如果可以 \(O(\log n)\) 查询子树权值和,则可以 \(O(d \log^2n)\) 得到重心,其中 \(d\) 为点的度数。
参考例题:ZJOI2015 幻想乡战略游戏
这道题找到重心后用动态点分治即可计算答案。
带权重心的神奇性质
与距离结合
从树上的任意一点作为起点,到树上所有点的距离乘上的终点点权,使它和最小的起点一定是树的带权重心。
值得一提的是如果乘的是 \(dist^k\) 依然成立。
证明
当前在重心 \(x\) 上,则若有一条边 \((x,y)\),设 \(x\) 侧权值和为 \(s_x\),\(y\) 侧为 \(s_y\)。
考虑转移到 \(y\),则多的贡献为 \(s_x-s_y\),由于重心,\(s_x\ge s_y\),因此 \(y\) 不优。
对于 \(dist^k\) 的情况可感性理解。
与 dfs 序上的带权中点结合
给定根,这里的重心是深度最小的重心。
首先建 dfs 序。
则将节点按 dfs 排列,这上面的带权中点在重心的子树内。
带权中点:将序列上权值求前缀和,第一个大于总权值和一半的点。
证明
深度最小的重心 \(G\) 的子树和 \(sz_G\) 大于 \(sum/2\)。
考虑 dfs 序 \(dfn\) 在 \(G\) 之前的点的权值和,一定小于 \(sum/2\)。
同时考虑 \(dfn\) 在 \(G\) 之后且不在 \(G\) 子树内的点的权值和,也一定小于 \(sum/2\)。
带权中点不在前也不在后,而在中间的子树内。
用带权中点 \(O(\log^2n)\) 动态维护区间修改权值的带权重心
同样的,这里的重心是深度最小的重心。
我们的区间修改权值显然是需要树剖的,我们的 \(dfn\) 要在树剖上建。
根据性质,找到带权中点,可以在线段树上二分,\(O(\log n)\)。
找到带权中点后,考虑倍增跳它的父亲。
由于此时我们所求的重心是子树大小 \(sz>sum/2\) 中深度最大的点,
于是考虑像倍增 LCA 那样,找到最远的在重心下面的点,重心就是它的父亲。
对于一个点 \(x\) 若 \(sz_x\le sum/2\),则它在我们的重心下面,于是往上跳。
最后取 \(fa_{x,0}\) 即可。
注意特判一下如果最开始的点 \(sz>sum/2\),则它就是重心。
我们每次 \(O(\log n)\) 求子树大小,跳 \(O(\log n)\) 次,于是就是 \(O(\log^2n)\)。
断边再加边的带权重心
如果我们断掉一条边 \((p,q)\),再加上一条边 \((u,v)\),考虑带权重心怎么变化。
首先新的图还是树的条件是:
假定 \(fa_p=q\),同时记 \(l_u=lca(p,u),l_v=lca(p,v)\),形成的新图为树的充要条件为 \([p=l_u]\oplus[p=l_v]=1\)。
然后考虑带权重心怎么变化,我们已经求出了改变前的带权重心 \(Rt\),我们以它为根给树确定方向。
假定 \(lca(u,p)=p\),那么如果 \(lca(v,p)=Rt\),则新的带权重心在 \((v,Rt)\) 这条路径上。
我们倍增从 \(v\) 开始跳,设 \(s_x\) 为 \(x\) 的子树权值和,如果 \(s[fa_{x,j}]+s[p]\le sum/2\) 则说明重心还在 \(fa_{x,j}\) 往上。
最后跳到 \(fa_{x,0}\)。注意如果 \(s_v+s_p>sum/2\) 则说明 \(v\) 已经是重心了。
而如果 \(lca(v,p)\ne Rt\),则相当于边的修改是在同一个子树内完成的,它并不影响整个树的重心,因此重心还是 Rt。
例题:信友队 NOIP2024 模拟 2024.11.25 场。