acwing-351. 树网的核
考点
- 树的直径
- 二分
- 单调队列
- 贪心
- 双指针
- 前缀和
题解
见思路
思路
首先证明两个直径的性质。
第一条,多条直径必相交于一点或一条公共路径。
假设A1到B1、A2到B2是两条不相交的直径,分别简写为l1和l2
根据树的连通性原理,A2肯定与l1的某个点C1连通,这样A2才能与A1、B1连通
问题来了,d == a + b,且都是最长长度(因为是直径),那么A1 - C1 - A2 - B2这条路径不是更长吗?!
长度高达a + c + d,相当于a + b + a + c,远大于a + b,
这与直径的定义相悖,得证。
第二条,任意两个同一侧的直径端点到相同直径分叉点的距离均相等。
假设有直径A1 - C - D - B1,还有直径A2 - C - D - B2,CD部分是共有的,长度设为t。
假设不平分,那么假设a > b,d > c,
显然得到a + d + t > b + c + t,也就是A2 - C - D - B1大于A1 - C - D - B2,这与直径的定义相悖。
所以a一定等于c,b也一定等于d。
证毕。
概括一下题意:
选一条直径,直径上选一段路径。
要让全树所有点,到这条路径的最大距离最小
由于本题所有的边权均为非负,那么直径的端点显然只能是叶子节点,否则还能再长。
整个树可以抽象如下:
1到2是一条直径,3到4是一条直径,5和6是直径分叉点,ABCDEF均为子树。
结合上述两条性质,选哪条直径对最大距离压根没有影响....
因为1 - 5和3 - 5距离完全相同,2 - 6和4 - 6距离也完全相同,其余子树都接在直径们的公共路径上。
所以直接两次BFS求出任意一条直径即可拿来做文章。
二分
最大值最小显然符合二分的性质,考虑验证条件。
设最大距离为mid,如果每个点到所选路径的最大距离都不会超过mid,验证成功。
设直径的两端点分别为p和q,令它俩各向内收缩mid距离,分别到达点u和v,作图所示。
如果
u - v路径长度大于s,说明不满足题意。子树
D在p - u路径上,子树E在q - v路径上,那么
D或E的任意点到u - v的路径长度都不可能大于mid,否则D 或 E - u - v - q能成为新的直径。换句话说,
p和q尽量向内收缩的过程中,顺带还能确保所经路径上的其他子树的最大距离不会超过mid!所以,如果
u > v,说明两侧子树到直径的任意子路径的最大长度都不会超过mid如果
u < v且u - v长度小于s,说明u - v这一段路径的子树的最大长度还需我们验证。(根据第2条,
p - u和q - v两条路径中的子树的最大长度必小于mid,无须验证)我们把直径上的所有点都设置为
已访问,然后令u - v这条路径上的所有点执行dfs求该点能到的最远距离,这样就能找到图上A、B、C等子树到
u - v的最远距离了。
1 |
|
单调队列与暴力
抛开二分,我们直接考虑最大距离最小的情况。
当i、j两个游标在直径上移动时,可以发现,当前的路径最大值取决于以下式子:
max(
p到游标i的距离,i到j路径中子树的最大距离,q到游标j的距离)
在固定i的情况下,j越大,q到j的距离肯定更小,所以有两种办法:
i与j维护一个单调队列,维护i到j之间子树的最大距离;只要
i到j的距离不超过s,j就一直向右扩张(贪心思路),在过程中比较上述式子。求最大值的运算具有结合律和分配律,两个游标一定会经过直径上的所有子树;
那倒不如直接暴力求出所有子树的最大距离,是个定值,记为
mx_d;然后
i、j俩游标正常移动,直接比较下述式子即可:max(
p到游标i的距离,mx_d,q到游标j的距离)
单调队列的写法
1 |
|
暴力的写法
1 |
|