我们知道很多树上的算法,但是在图上却难以实现,这个时候是不是就会想把图变成树呢?
这里介绍一个把无向图转化成树的方法,就是 圆方树。
1. 建树原理
(Tips : 若无需“导读”可以直接往下翻至1.4节)
1.1 缩点
我们不妨先回顾一下,我们有什么方法把一张任意的有向图变成有向无环图(DAG)的?
比较熟悉的方法就是tarjan
缩点。
所以我们对于无向图,我们也先缩点——把点双连通分量缩在一起。
特别注意,我们要把只有一条边,只连接 2 2 2个点的“伪点双”也要算进去。
1.2 建点
即使把点双缩起来了,我们得到的依然是一张无向图——那怎么把它统领成树呢?很容易想到就是对于这个缩好之后的点新建一个点,我们称之为方点。
那么对应的缩点前原图的点就称之为圆点。
1.3 重建
这时图就显得很杂乱了,为了保证这个树建出来有用,我们需要整理一下,具体方案如下:
- 拆掉每个点双内部的所有边。
- 将这个点双对应的方点向这个点双内的每一个圆点连一条边。
1.4 总结
简而言之,记原图点为圆点,建立圆方树就是找出每一个点双,然后建一个对应这个点双的方点,方点连向每一个点双内的圆点,删去每个点双内部圆点原有的连边。这样每一个点双就成为了一个树的形态,这样所有的都连起来也就是一颗树了。
(这里特别解释一下怎么“全部连起来”。实际上并不需要额外的操作。就是因为我们把只有 2 2 2个点 1 1 1条边的也算进去,因此相邻点双之间都会有公共点。然后两个点双就会是以“方点 1 → _1 \to 1→ 公共点 → \to → 方点 2 _2 2 ”的顺序自然连接。)
2. 性质
这个圆方树肯定有一些特别的性质嘛,不然要了干什么……
- 对于任意无向图 G = { V , E } G=\{V , E\} G={ V,E}均满足建出来的是森林;
- 对于任意连通无向图 G G G均满足建出来的是一颗无根树;
- 对于每一个圆点,都对应着有且仅有一个方点;
- 对于任意一条路径,路径上的圆点和方点都是相间出现,或者说同种形状的点不相邻。
- 原图的割点是圆方树中度数 > 1 >1 >1的圆点。
这些性质都是很显然的,无需过多证明。第 4 4 4个性质是之前多次强调的 2 2 2个点 1 1 1条边的特殊点双保证的。
3. 实现
以上为理论部分,实现上还有一些细节需要注意的。
- 点权 w i w_i wi,一般在题目中我们会给每一个点赋予一个点权,然后根据圆方树的性质,操作这些点权。
- 子树大小 s z i sz_i sz