P5666 [CSP-S2019] 树的重心

发布时间 2023-11-01 09:22:34作者: 御坂夏铃

考虑一个结点在什么情况下会成为重心。

随便钦定一个根结点。对于结点 \(u\),假设割掉了其子树 \(v\) 中的某条边或连接 \(u\)\(v\) 的边,形成了一棵大小为 \(k\) 的新树。

\(mx\) 表示除 \(v\) 子树外最大的子树大小(或 \(n-siz_u\))。如果 \(u\) 成为了重心根据定义有 \(2\times\max(mx,siz_v-k)\leq n-k\)

整理一下就变成 \(2\times siz_v-n\leq k\leq n-2\times mx\)

对于割掉 \(u\) 子树外面的边的情况,类似可以得出 \(2\times\max(mx,n-siz_u-k)\leq n-k\)

整理一下就变成 \(n-2\times siz_u\leq k\leq n-2\times mx\)

对于前一种情况,dsu on tree 维护一个树状数组计算可以割掉的子树数量。

对于后一种情况,先将全部子树扔进树状数组,然后在 DFS 的过程中不断更新(和换根 DP 一样)。不过我们只能得到当前子树内和子树外的和,所以得在前面 dsu on tree 的时候提前减掉子树内的部分。

注意上界大部分都是一样的,后一种情况的下界则都是一样的,所以可以记下来避免多次查询,常数会变小很多。

当然两只 \(\log\) 赛场上不一定过得去,考虑继续优化。


发现要维护的信息可以直接进行简单的加减得到,所以没有必要使用 dsu on tree,依次累加,离开某个子树时的答案减去进入该子树时的答案即是该子树内的答案。

我真是个傻逼

还有 \(O(n)\) 做法,好像是直接考虑重心的移动过程,具体可以去看题解。