模拟赛被信息差了,正解想到了但不知道圆方树最终获得了暴力分遗憾离场,故记录于此。
小号保存的文章不考虑删除。
点双连通分量
声明:一种定义是“图中任意两不同点之间都有至少两条点不重复的路径”,而另外一种是“不存在割点的图”,这两种定义存在细微差别,具体体现在两个点之间有一条连边构成的图。但是一般情况下我们讨论的都是长度 >2\gt 2>2 或者有关割点的问题,所以采用第二种定义。
首先回顾求割点的方法:递归,若 uuu 点 dfs 树儿子存在 lowv≥dfnu\text{low}_v\ge \text{dfn}_ulowv ≥dfnu ,则该点为割点。
还要注意特判一下 dfs 到的第一个点的情况,因为它没有父亲节点,所有点对于它来说 low\text{low}low 一定是大的,但这并不能说明它是割点。只有当要 dfs 至少两次时它才是这几个 dfs 的块的割点。
那么点双连通分量应该怎么求呢?
我们可以用有向图强连通分量类似的方法,用栈维护强连通分量。
具体地,我们开一栈,在递归到一个点 uuu 时,我们将它入栈。然后我们访问它的所有树儿子,如果发现这个点与树儿子 vvv 满足 lowv≥dfnu\text{low}_v\ge \text{dfn}_ulowv ≥dfnu ,那么说明这个点是割点,与下面的节点形成一个点双联通分量。
但是这时,虽然树根可能不是割点,但它一定与下面的点构成一个点双连通分量,所以和上面的一样,不需要特判。
这里直接偷洛谷第一篇题解的图,根据图自己理解一下。
时间复杂度:O(n+m)O(n+m)O(n+m)。
诶等等,这是不是叫 dcc 来着,变量名写错了(((
圆方树
这为啥是紫的?但是水紫它不香吗(
求出所有点双联通分量后建每个分量对应的虚点(记为“方点”),虚点与所属点双的每个点(记为“圆点”)连边,会形成一棵树。然后这棵树就相当于点双连通分量缩点之后的树,但是很好地保留了原树的形态。
例题(模拟赛题,特殊性质 B):
给定一张 nnn 个点 mmm 条边的无向图,其中 kkk 个点被封锁,分别为 A1,A2,...AkA_1,A_2,...A_kA1 ,A2 ,...Ak 。被封锁的点可以到达,但是不可以走出。定义 f(i)f(i)f(i) 代表额外封锁节点 i(i∉A)i(i\not\in A)i(i∈A) 后,从 111 开始可以到达的被封锁点的数量。对于 i=1,2,3,...,ni=1,2,3,...,ni=1,2,3,...,n,分别求出 f(i)f(i)f(i) 的值。如果不存在,输出 −1-1−1。
考虑先在图中删除所有 AiA_iAi ,并对删除后的图跑个点双连通分量。根据定义,显然如果封锁的点在点双连通分量的内部,则不会影响,都能到达(除了一开始就被其他 AiA_iAi 堵住的);否则被封锁的点一定是割点。
现在的问题转化成了,删除这个点后,有多少个 AiA_iAi 会被影响不能到达。
赛时的想法是,直接对点双缩点建树,大力分讨,但码量过于巨大。
我们考虑对这个图建一棵圆方树,则 AiA_iAi 被影响当且仅当这个点在原图中所有邻居在圆方树 →1\to 1→1 的路径的公共点中,由于这是一棵树,所以显然是以 111 为根,所有邻居的 LCA →1\to 1→1 的路径。
然后做个树上差分即可。
时间复杂度:O(m+nlogn)O(m+n\log n)O(m+nlogn)。