“浅谈”圆方树
圆方树的引入
我们知道,图没有很好的性质,而树有很多性质,并且容易通过很多方式来维护树上信息,因此将图上问题转化为树上问题是我们想要解决的。圆方树就是将图转化为树的数据结构。
圆方树的分类
圆方树分为两类:狭义圆方树,广义圆方树。
狭义圆方树
狭义圆方树是可以用来将仙人掌图转化为树的一种数据结构。
广义圆方树
广义圆方树是可以用来将所有无向图转化为树的一种数据结构。
狭义圆方树
作者还没学广义圆方树,所以先来讲狭义圆方树。
仙人掌图
什么是仙人掌图?这里给出定义:
任意一条边至多只出现在一条简单回路的无向连通图称为仙人掌。
简单来说,就是图中有环并且图中任意两个环没有公共边的图。
如果你还不懂的话请看下图。
建树
我们回顾 Tarjan 算法。
在无向图中,Tarjan 算法找到图中的环,并且将环缩成一个点,这样就将原来的无向图变成了一棵树。
那这里你可能会问,那我还要圆方树干嘛,有 Tarjan 不就够了吗?还真不行,因为 Tarjan 将环都缩成一个点了,因此原来环上的很多信息你都没有办法保留了,所以在面对很多问题时就用不了了。
但是 Tarjan 算法给我们启发:可以将环看成一个整体。
于是产生了圆方树。
如图,原图中的每一个点看作一个圆点,而每一个环看作一个方点。
这时候我们将原来的边删去,每个圆点与它所在的环对应的方点之间连一条边,这就建好了一棵圆方树。
由于仙人掌图保证图中没有两个环有公共边,因此圆方树中也就不会有两个相邻的方点。
那么这个时候你可能会问,你这圆方树没有边权啊,我们这就来解决边权问题。
如图所示,我们设 7 号节点为根节点。
图中 3 号节点就是环内距离根节点最近的点。像这样距离根节点最近的点,我们令它为 X 节点。
那么就有一条性质:环上各点到根节点一定经过 X 节点。
环内各点到 X 节点有两种方向,一种是顺时针,另一种是逆时针。而这两种方向对应的路径一定是环内各点到 X 节点的最短路以及最长路。
一般来说,我们不需要维护最长路的信息,因此我们只保留最短路的信息,就像下面这棵圆方树。
原图中 1 到 3 的最短路径是 1−4−3,长度为 2,圆方树上 1 到 3 的距离也是 2,就是说我们保留的信息无误。
具体实现
在 Tarjan 算法中,我们找环用的是边双连通分量,边双连通分量是指将割边删除后的连通块。
那么我们发现原图中的 1∼6 这 6 个点都属于边双连通分量。但是它们并不属于同一个环啊,因此我们需要改进 Tarjan 算法。
如图所示,黑色边是 Tarjan 的搜索树,红色边是非树边,即没有被遍历的边。
对于每个点,我们存储每个点的父亲,同时我们将这个点到它父亲的边的边权给这个点。
如果 dfnx<dfny,说明 x 比 y 先被遍历,同时如果 fay≠x,说明 x 到 y 不止一条路径,即存在环,那么我们就成功找到环了。就像上图中 1 和 5 之间的关系。
然后就像上面说的一样建边就好了。
接下来该处理边权问题。
由于我们找到了环,因此我们在环内绕着一个方向一直走,这样我们可以得到每个点沿着这个方向到达 X 节点的距离 disi 以及整个环的长度 d。
那么我们之前说了,顺时针和逆时针走对应的长度是最长路以及最短路,因此我们要保留最短路只需要比较当前节点到 X 节点的距离以及用环长减去当前距离就是最短路了。
即:
min(disi,d−disi)
然后就成功拿下圆方树了。
各种毒瘤组合
前面说了,圆方树将图上问题转化为树上问题,然后就可以套各种各样的毒瘤算法。
- 点分治
- 树上公共祖先
- 树链剖分
- 动态树
- …
例题
P5236 【模板】静态仙人掌/AcWing 360. Freda的传呼机
题目描述
给你一个有 n 个点和 m 条边的仙人掌图,和 q 组询问,每次询问两个点 x,y,求两点之间的最短路。
具体思路
首先我们先建一棵圆方树,那么问题就转化为在树上求最短路。显然 LCA 啊。
- 若 LCA(x,y) 是圆点,那么这个点是原图上的点,直接就 LCA 即可。
- 若 LCA(x,y) 是方点,那么这个点不属于原图,我们需要将方点转化为圆点。
容易想到的是求出这个方点的两个儿子 lc 和 rc,这个用倍增算法很容易求出。
那么问题转化为:
dis(x,y)=dis(x,lc)+dis(y,rc)+dis(lc,rc)
dis(x,lc) 和 dis(y,rc) 用倍增就可以解决,而 dis(lc,rc) 我们在建圆方树时就已经求出了。
Code
本文来自博客园,作者:FChang,转载请注明原文链接:https://www.cnblogs.com/FChang/p/18823066







浙公网安备 33010602011771号