树的重心

树的重心

本文介绍了树的重心及其性质、如何动态维护修改权值的带权重心、如何寻找断边再加边的带权重心。


无根树的重心定义为:

\(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)\)

例题:JZOJ 7469 数据结构

断边再加边的带权重心

如果我们断掉一条边 \((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 场。

posted @ 2024-11-26 08:15  dengchengyu  阅读(9)  评论(0编辑  收藏  举报