[BZOJ5329][Sdoi2018]战略游戏(圆方树+虚树)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=5329

Solution

首先介绍一下圆方树。
先求点双连通分量,设原图中的点为圆点。
然后对于每个点双连通分量建一个方点,从方点向连通分量内的所有点连一条边,并把这个连通分量里原有的边删掉。
在 Tarjan 求点双的过程中,所有点分别入栈了一次,而除了根之外所有的点都出栈了一次,设有 m 个点双,那么除了出栈过的 n 1 个点进入点双之外,每次找到连通分量时还要把一个割点算入,这样所有点双的点数之和为 n + m 1 ,而上面的构图中圆点和方点的总数为 n + m ,所以得出,这样得到的是一棵树,这棵树就是圆方树。
圆方树有一些神奇的性质:
(1)原图的割点对应圆方树的割点(方点除外),也就是属于多个方点的圆点。
(2)两个点 u , v 之间的割点集合为圆方树 u v 的路径上除 u v 的所有圆点。
回到问题。建出圆方树,可以把问题进行转化。
求一个点集之间两两的路径的并上,有多少个圆点(这个选出的点集除外)。
点集之间两两的路径并实际上就是这个点集构成的虚树。
把关键点按 DFS 序排序后我们要求的就是求相邻两个点之间路径的并。
我们给每条边一个权值: ( u , v ) 边,如果深度较大的点 v 为圆点则 ( u , v ) 的权值为 1 ,否则为 0
这样,问题再次转化:
求点集 S 所在虚树的边权和,减去 | S | 如果虚树的根为圆点则加一
容易想到,点集 S 的虚树的边权和,
就是 DFS 序排序之后 1 2 2 3 ,…, | S | 1 S S 1 的路径边权之和除以 2
利用倍增 LCA 即可求得。

Code

cpp

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81395001