看某个ppt的时候看到了这个东西,就产生了一些兴趣。
这个东西似乎有点鸡肋,我做了这么久的题,没有见过一道是用支配树解决的。
不过这个算法真的很有趣。
现在我还没有学完。打打博客加深理解。
先推荐一篇很好的博客
什么是支配树?
现在我给你一个起点为
r
r
r的有向图,你需要求各种有关必经点的问题。
先说一堆概念:
支配点:对于一个点
x
x
x,如果
r
r
r到
x
x
x的所有路径上经过
y
y
y,那么
y
y
y支配
x
x
x
最近支配点:对于一个点
x
x
x,如果有一个点
y
y
y满足
y
y
y支配
x
x
x,并且所有支配
x
x
x的平凡支配点全都支配
y
y
y,那么
y
y
y就是
x
x
x的最近必经点,记作
i
d
o
m
(
x
)
idom(x)
idom(x)
平凡支配点就是除了
x
x
x,之外的所有支配点。(其实网上的其它博客说
r
r
r也不包括在内,不过我觉得这样方便理解)
定理1:对于任意的点,它的最近支配点都是唯一的。
证明:假设这个点是 x x x,它有两个最近支配点分别为 y y y和 z z z
由定义得 z z z支配 y y y,并且 y y y支配 z z z。
因为 y ≠ z y\neq z y̸=z,所以矛盾
这个证明是不是特别简略……
既然每个点的最近支配点都是唯一的,那我们自然而然地想到可以建立一棵树。
对于点
x
x
x,将
i
d
o
m
(
x
)
idom(x)
idom(x)作为自己的父亲,方向为
i
d
o
m
(
x
)
idom(x)
idom(x)到
x
x
x。
这就是支配树。
性质?
对于一个点
x
x
x,所有支配它的点都是它在支配树上的祖先。
所以说我们可以利用它这个奇妙的性质做各种各样有关必经点的事情。
知道了支配树的功能,现在我们的主要问题是,如何建立支配树。
建立支配树就需要更多的概念和性质……
更加详细的性质
首先,从
r
r
r开始,建立一棵dfs树。
显然这个dfs树并不是支配树……
记录一下它们的dfs序,在后面的叙述中,我直接用dfs序来表示它们的编号。
一棵图中的边
(
x
,
y
)
(x,y)
(x,y)有四种情况:树枝边(这里指的是dfs树),前向边(
x
x
x是
y
y
y的祖先),后向边(
x
x
x是
y
y
y的后代),横插边(显然
x
>
y
x>y
x>y)。
接下来我们用几个符号来表示各种关系(这个一定要记住):
a
→
b
a\to b
a→b表示
a
a
a能直接通过一条边到达
b
b
b
a
⇝
b
a \leadsto b
a⇝b表示
a
a
a能通过某条路径到达
b
b
b
a
→
˙
b
a \dot \to b
a→˙b表示
a
a
a能通过树枝边到达
b
b
b
a
→
+
b
a \overset{+}{\to}b
a→+b表示
a
→
˙
b
a \dot \to b
a→˙b并且
a
≠
b
a\neq b
a̸=b
引理1(路径引理)
对于两个点
v
v
v和
w
w
w,若
v
≤
w
v\leq w
v≤w,那么
v
v
v到
w
w
w的路径上必定经过他们的公共祖先(也就是
L
C
A
(
v
,
w
)
LCA(v,w)
LCA(v,w)及其所有祖先)
证明:如果 v v v是 w w w的祖先,显然成立。
因为横插边都是从大点去到小点,所以不可以通过横插边从 v v v所在的子树到达 w w w所在的子树。
所以只能通过后向边跳上公共祖先,然后从公共祖先通过前向边跳下来。
半支配点
对于
w
≠
r
w\neq r
w̸=r,都有一个半支配点
s
d
o
m
(
w
)
sdom(w)
sdom(w)
s
d
o
m
(
w
)
=
min
{
v
∣
∃
(
v
0
,
v
1
,
⋯
 
,
v
k
−
1
,
v
k
)
,
v
0
=
v
,
v
k
=
w
,
∀
1
≤
i
≤
k
−
1
,
v
i
>
w
}
sdom(w)=\min\{ v | \exists (v_0,v_1,\cdots,v_{k-1},v_k), v_0 = v, v_k = w, \forall 1 \leq i \leq k-1, v_i>w \}
sdom(w)=min{v∣∃(v0,v1,⋯,vk−1,vk),v0=v,vk=w,∀1≤i≤k−1,vi>w}
也就是说,从
s
d
o
m
(
w
)
sdom(w)
sdom(w)开始,存在一条从
s
d
o
m
(
w
)
sdom(w)
sdom(w)到
w
w
w的路径,使得中间经过的所有点都比
w
w
w大。
注意,半支配点并不一定是支配点,可能是支配点。
引理2:
对于任意
w
≠
r
w\neq r
w̸=r,满足
i
d
o
m
(
w
)
→
+
w
idom(w) \overset{+}{\to} w
idom(w)→+w
(证明显然:如果不是这样,它就可以直接通过树枝边来到达
w
w
w了,与定义矛盾)
引理3:
对于任意
w
≠
r
w\neq r
w̸=r,满足
s
d
o
m
(
w
)
→
+
w
sdom(w) \overset{+}{\to} w
sdom(w)→+w
证明:首先, f a w fa_w faw是 s d o m ( w ) sdom(w) sdom(w)的一个候选,因为中间没有任何的点落脚。
所以 s d o m ( w ) ≤ f a w sdom(w)\leq fa_w sdom(w)≤faw
根据路径引理,如果 s d o m ( w ) sdom(w) sdom(w)在另一棵子树,那么必定经过他们的公共祖先,公共祖先小于 x x x,与定义矛盾
引理4:
对于任意
w
≠
r
w \neq r
w̸=r,满足
i
d
o
m
(
w
)
→
˙
s
d
o
m
(
w
)
idom(w) \dot \to sdom(w)
idom(w)→˙sdom(w)
证明:如果不是这样,那么存在路径 r ⇝ s d o m ( w ) ⇝ w r\leadsto sdom(w)\leadsto w r⇝sdom(w)⇝w,
s d o m ( w ) ⇝ w sdom(w)\leadsto w sdom(w)⇝w不经过 i d o m ( w ) idom(w) idom(w),与 i d o m idom idom的定义矛盾
引理5:
对于满足
v
→
˙
w
v \dot \to w
v→˙w的点
v
v
v和
w
w
w,
v
→
˙
i
d
o
m
(
w
)
v \dot \to idom(w)
v→˙idom(w)或
i
d
o
m
(
w
)
→
˙
i
d
o
m
(
v
)
idom(w)\dot \to idom(v)
idom(w)→˙idom(v)
这个似乎有点不好理解,其实可以根据上面的几个引理画出来:
i
d
o
m
(
v
)
→
+
v
→
˙
i
d
o
m
(
w
)
→
+
w
idom(v) \overset{+}{\to}v\dot \to idom(w)\overset{+}{\to}w
idom(v)→+v→˙idom(w)→+w
i
d
o
m
(
w
)
→
˙
i
d
o
m
(
v
)
→
+
v
→
˙
w
idom(w) \dot \to idom(v) \overset{+}{\to}v\dot \to w
idom(w)→˙idom(v)→+v→˙w
也就是
i
d
o
m
(
v
)
→
+
v
idom(v)\overset{+}{\to}v
idom(v)→+v要么被
i
d
o
m
(
w
)
→
+
w
idom(w)\overset{+}{\to}w
idom(w)→+w包含,要么不相交。(这样说不严谨,因为端点可能会重合)
证明:如果不是这样,那么 i d o m ( v ) → + i d o m ( w ) → + v → + w idom(v) \overset{+}{\to} idom(w)\overset{+}{\to} v\overset{+}{\to} w idom(v)→+idom(w)→+v→+w
存在 r → ˙ i d o m ( v ) ⇝ v → + w r \dot \to idom(v) \leadsto v \overset{+}{\to} w r→˙idom(v)⇝v→+w。( i d o m ( w ) idom(w) idom(w)是 i d o m ( v ) idom(v) idom(v)的真后代,不支配 v v v。所以可以绕过 i d o m ( w ) idom(w) idom(w)到达 w w w)
与 i d o m idom idom的定义矛盾。
这后面的会难一些,不对,是难很多。
揭示了
i
d
o
m
idom
idom和
s
d
o
m
sdom
sdom的关系
定理2:
对于任意
w
≠
r
w\neq r
w̸=r,如果所有满足
s
d
o
m
(
w
)
→
+
u
→
˙
w
sdom(w)\overset{+}{\to}u\dot \to w
sdom(w)→+u→˙w的
u
u
u也满足
s
d
o
m
(
w
)
≤
s
d
o
m
(
u
)
sdom(w)\leq sdom(u)
sdom(w)≤sdom(u),则
i
d
o
m
(
w
)
=
s
d
o
m
(
w
)
idom(w)=sdom(w)
idom(w)=sdom(w)
画一下就是:
s
d
o
m
(
w
)
→
˙
s
d
o
m
(
u
)
→
+
u
→
˙
w
sdom(w)\dot \to sdom(u) \overset{+}{\to} u \dot \to w
sdom(w)→˙sdom(u)→+u→˙w
证明:由定理4得 i d o m ( w ) → ˙ s d o m ( w ) idom(w) \dot \to sdom(w) idom(w)→˙sdom(w),所以如果我们想要证明 i d o m ( w ) = s d o m ( w ) idom(w)=sdom(w) idom(w)=sdom(w),就只需要证明 s d o m ( w ) sdom(w) sdom(w)支配 w w w即可。
对于任意从 r r r到 w w w的路径,取最后一个小于 s d o m ( w ) sdom(w) sdom(w)的点 x x x。
假设 y y y是 x x x的后继
由于 x x x是最后一个小于 s d o m ( w ) sdom(w) sdom(w)的点,所以 s d o m ( w ) ≤ y sdom(w) \leq y sdom(w)≤y。
由 s d o m sdom sdom的定义得,必定存在 y y y满足 s d o m ( w ) → ˙ y → ˙ w sdom(w)\dot \to y \dot \to w sdom(w)→˙y→˙w(否则 x x x就是 s d o m ( w ) sdom(w) sdom(w))
取最小的 y y y,假设 y y y不是 s d o m ( w ) sdom(w) sdom(w)
由条件得 s d o m ( w ) ≤ s d o m ( y ) sdom(w)\leq sdom(y) sdom(w)≤sdom(y),由于 x < s d o m ( w ) x< sdom(w) x<sdom(w),所以 x ≠ s d o m ( y ) x\neq sdom(y) x̸=sdom(y)
所以存在 x → + t → + y x\overset{+}{\to} t\overset{+}{\to} y x→+t→+y,由于 x x x是最后一个小于 s d o m ( w ) sdom(w) sdom(w)的点,所以 s d o m ( w ) → ˙ t → ˙ w sdom(w)\dot \to t \dot \to w sdom(w)→˙t→˙w
在前面已经说过 y y y是最小的,所以矛盾
因此 y y y就是 s d o m ( w ) sdom(w) sdom(w)
所以任意路径经过 s d o m ( w ) sdom(w) sdom(w),因此 s d o m ( w ) sdom(w) sdom(w)支配 w w w。
即 i d o m ( w ) = s d o m ( w ) idom(w)=sdom(w) idom(w)=sdom(w)
这是前面说过的参考博客的证明,但是我感觉这种证明有点问题。
于是自己用另一种方法证明了一遍:
证明:我们同样是证明 s d o m ( w ) sdom(w) sdom(w)支配 w w w
反证法,假设存在路径绕过 s d o m ( w ) sdom(w) sdom(w)到达 w w w
这条路径必定可以看作,从 r r r绕过 s d o m ( w ) sdom(w) sdom(w)到达点 x x x(满足 s d o m ( w ) → + x → ˙ w sdom(w)\overset{+}{\to}x \dot \to w sdom(w)→+x→˙w),然后直接到 w w w。
1、当从某个比 x x x大的点来到 x x x时,由于 s d o m ( w ) ≤ s d o m ( x ) sdom(w) \leq sdom(x) sdom(w)≤sdom(x),所以 s d o m ( w ) → ˙ s d o m ( x ) sdom(w) \dot \to sdom(x) sdom(w)→˙sdom(x),不可能直接通过树枝边从 r r r到达 s d o m ( x ) sdom(x) sdom(x),不存在这样的路径。
2、当从某个比 x x x小的点来到 w w w时,
(1)如果从树枝边走来:
如果 x x x是 s d o m ( w ) sdom(w) sdom(w)的儿子,那么 s d o m ( x ) = s d o m ( w ) sdom(x)=sdom(w) sdom(x)=sdom(w),所以不能到达。
用归纳证明的思想,可得后面的点都不能到达。所以这个点不能在 s d o m ( w ) sdom(w) sdom(w)和 w w w之间的路径上。
(2)如果从 s d o m ( w ) sdom(w) sdom(w)的子树外走来
这个点显然可以作为 s d o m ( x ) sdom(x) sdom(x)的取值,但是 s d o m ( w ) ≤ s d o m ( x ) sdom(w)\leq sdom(x) sdom(w)≤sdom(x),矛盾
综上,这种路径不存在。
可能还是有点不严谨,不过理解一下就好。
定理3:
对于任意
w
≠
r
w\neq r
w̸=r,设
u
u
u为满足
s
d
o
m
(
w
)
→
+
u
→
˙
w
sdom(w) \overset{+}{\to} u \dot \to w
sdom(w)→+u→˙w的
s
d
o
m
(
u
)
sdom(u)
sdom(u)最小的
u
u
u,如果sdom(u)
≤
s
d
o
m
(
w
)
\leq sdom(w)
≤sdom(w),那么
i
d
o
m
(
w
)
=
i
d
o
m
(
u
)
idom(w)=idom(u)
idom(w)=idom(u)
画图:
s
d
o
m
(
u
)
→
˙
s
d
o
m
(
w
)
→
+
u
→
˙
w
sdom(u) \dot \to sdom(w) \overset{+}{\to} u \dot \to w
sdom(u)→˙sdom(w)→+u→˙w
证明:由引理5得 i d o m ( w ) → ˙ i d o m ( u ) idom(w) \dot \to idom(u) idom(w)→˙idom(u)或 u → ˙ i d o m ( w ) u\dot \to idom(w) u→˙idom(w),由引理 4 4 4得后面的这种情况不存在。
画张图理解一下: i d o m ( w ) → ˙ i d o m ( u ) → ˙ s d o m ( w ) → + u → ˙ w idom(w)\dot \to idom(u) \dot \to sdom(w)\overset{+}{\to}u \dot \to w idom(w)→˙idom(u)→˙sdom(w)→+u→˙w
所以,我们要证明 i d o m ( w ) = i d o m ( u ) idom(w)=idom(u) idom(w)=idom(u),只需要证明 i d o m ( u ) idom(u) idom(u)支配 w w w即可。
类似于之前的思路:
假设有某一条路径绕过 i d o m ( u ) idom(u) idom(u)到达 w w w
1、从大于 w w w点到达 w w w
如果这样,存在一个点 x x x,满足 s d o m ( w ) sdom(w) sdom(w)的定义(不一定最小)。
如果 x → + u x \overset{+}{\to} u x→+u,
因为 i d o m ( u ) idom(u) idom(u)支配 u u u,而又存在 r ⇝ x → + u r \leadsto x \overset{+}{\to} u r⇝x→+u,所以 i d o m ( u ) idom(u) idom(u)支配 x x x。
所以不存在某种绕过 s d o m ( w ) sdom(w) sdom(w)到达 x x x的方案。
如果 u → ˙ x u\dot \to x u→˙x,那么继续考虑能不能到达 x x x(像个递归的过程),最终总会到 x → + u x\overset{+}{\to} u x→+u的状况,因此也是不存在的。
2、从小于 w w w点到达 w w w
(1)从树枝边走来
类似于之前的情况,如果存在这样的路径,必定能从起点绕过 i d o m ( u ) idom(u) idom(u)到达 u u u和 w w w之间的某个点。(前面已经证明过绕 i d o m ( u ) idom(u) idom(u)到达 i d o m ( u ) idom(u) idom(u)和 u u u之间的点不存在)
但是连 s d o m ( u ) sdom(u) sdom(u)最小的 u u u都不成立,那其他的点也不可能了。
(2)从 i d o m ( u ) idom(u) idom(u)外走来
如果可以这么走,那它就应该是 s d o m ( w ) sdom(w) sdom(w),矛盾。
综上所述,不存在这样的路径
推论1
对于任意
r
≠
w
r\neq w
r̸=w,如果有满足
s
d
o
m
(
w
)
→
+
u
→
˙
w
sdom(w) \overset{+}{\to} u \dot \to w
sdom(w)→+u→˙w且
s
d
o
m
(
u
)
sdom(u)
sdom(u)最小的
u
u
u,那么
i
d
o
m
(
w
)
=
{
s
d
o
m
(
w
)
(
s
d
o
m
(
u
)
=
s
d
o
m
(
w
)
)
i
d
o
m
(
u
)
(
s
d
o
m
(
u
)
<
s
d
o
m
(
w
)
)
idom(w) = \left \{ \begin{aligned}& sdom(w)&(sdom(u)=sdom(w))&\\ &idom(u)&(sdom(u)<sdom(w))&\end{aligned} \right .
idom(w)={sdom(w)idom(u)(sdom(u)=sdom(w))(sdom(u)<sdom(w))
这个东西是通过上面的定理2和定理3推过来的。但是在这里,我们发现
s
d
o
m
(
u
)
≤
s
d
o
m
(
w
)
sdom(u)\leq sdom(w)
sdom(u)≤sdom(w)的,为什么呢?
我感觉博客中简略的证法好像有问题,所以我自己想了一下:
证明:如果存在某种情况使得 s d o m ( u ) > s d o m ( w ) sdom(u)>sdom(w) sdom(u)>sdom(w)
画图就是这样: s d o m ( w ) → + s d o m ( u ) → + u → ˙ w sdom(w) \overset{+}{\to} sdom(u) \overset{+}{\to} u \dot \to w sdom(w)→+sdom(u)→+u→˙w
显然 s d o m ( s d o m ( u ) ) < s d o m ( u ) sdom(sdom(u))<sdom(u) sdom(sdom(u))<sdom(u),所以此时的 s d o m ( u ) sdom(u) sdom(u)应该是 u u u。
我们已经要求过 s d o m ( u ) sdom(u) sdom(u)最小,所以矛盾。
因此 s d o m ( u ) ≤ s d o m ( u ) sdom(u)\leq sdom(u) sdom(u)≤sdom(u)
如果暴力求
s
d
o
m
sdom
sdom则太慢,于是就有了下面这个强大的定理:
定理4:
对于任意
w
≠
r
w\neq r
w̸=r,
s
d
o
m
(
w
)
=
m
i
n
(
{
v
∣
(
v
,
w
)
∈
E
,
v
<
w
}
∪
{
s
d
o
m
(
u
)
∣
u
>
w
,
∃
(
v
,
w
)
∈
E
,
u
→
˙
v
}
)
sdom(w) = min(\{v | (v, w) \in E , v < w \} \cup \{sdom(u) | u > w , \exists (v, w) \in E , u \dot \to v\} )
sdom(w)=min({v∣(v,w)∈E,v<w}∪{sdom(u)∣u>w,∃(v,w)∈E,u→˙v})
其实这个东西特别像是一个递推式。
别人博客上有证明,我理解式子后,第一反应是,这个东西需要证明?
如果仅仅把它当作一个递推式来看,那么它还是特别好理解的。
证明一下吧……
证明:设等号右边的式子的结果为 x x x,显然 s d o m ( w ) ≤ x sdom(w)\leq x sdom(w)≤x。现在要证明 x ≤ s d o m ( w ) x\leq sdom(w) x≤sdom(w)
如果 s d o m ( w ) sdom(w) sdom(w)到 w w w中只经过一条边,显然 ( s d o m ( w ) , w ) ∈ E (sdom(w),w)\in E (sdom(w),w)∈E且 s d o m ( w ) < w sdom(w)<w sdom(w)<w,所以 x ≤ s d o m ( w ) x\leq sdom(w) x≤sdom(w)
如果不只经过一条边,设这条路径上的最后一个点为 l a s t last last。在 s d o m ( w ) sdom(w) sdom(w)和 l a s t last last之间找到一个最小的点 p p p,显然 s d o m ( w ) sdom(w) sdom(w)到 p p p上经过的点都比 p p p大,所以 s d o m ( p ) ≤ s d o m ( w ) sdom(p)\leq sdom(w) sdom(p)≤sdom(w)。
同时 s d o m ( p ) sdom(p) sdom(p)满足等式右边的条件,满足 p → ˙ l a s t p\dot \to last p→˙last, ( l a s t , w ) ∈ E (last,w)\in E (last,w)∈E。
所以 s d o m ( p ) sdom(p) sdom(p)是 x x x的一个候选,所以 x ≤ s d o m ( p ) ≤ s d o m ( w ) x\leq sdom(p)\leq sdom(w) x≤sdom(p)≤sdom(w),所以 x ≤ s d o m ( w ) x \leq sdom(w) x≤sdom(w)
综上, x ≤ s d o m ( w ) x\leq sdom(w) x≤sdom(w)。
所以 s d o m ( w ) = x sdom(w)=x sdom(w)=x
Lengauer-Tarjan算法
前面推的东西都是为这个算法铺垫的。这个算法用到定理4和推论1。
先说说步骤:
1、dfs一遍,求出
d
f
n
dfn
dfn。
2、按照
d
f
n
dfn
dfn倒着求出
s
d
o
m
sdom
sdom。
3、确定
i
d
o
m
=
s
d
o
m
idom=sdom
idom=sdom的
i
d
o
m
idom
idom,其它的暂时不理它。
4、按照
d
f
n
dfn
dfn顺着找没有计算的
i
d
o
m
idom
idom,计算。
第1步不说。
第2步和第3步可以放在一起来写。
我们要用一个数据结构来维护一个森林,每个点到根的路径上最小的
s
d
o
m
sdom
sdom。这个数据结构可以用并查集。我们记作
x
x
x的这个东西为
e
v
a
l
(
x
)
eval(x)
eval(x)
看看定理4的式子:
s
d
o
m
(
w
)
=
m
i
n
(
{
v
∣
(
v
,
w
)
∈
E
,
v
<
w
}
∪
{
s
d
o
m
(
u
)
∣
u
>
w
,
∃
(
v
,
w
)
∈
E
,
u
→
˙
v
}
)
sdom(w) = min(\{v | (v, w) \in E , v < w \} \cup \{sdom(u) | u > w , \exists (v, w) \in E , u \dot \to v\} )
sdom(w)=min({v∣(v,w)∈E,v<w}∪{sdom(u)∣u>w,∃(v,w)∈E,u→˙v})
由于我们是倒过来做的,所以对于点
w
w
w来说,若它的前驱
v
>
w
v>w
v>w,那么上式右边的
u
u
u取
e
v
a
l
(
v
)
eval(v)
eval(v)是最合适的。如果前驱
v
<
w
v<w
v<w,它们没有处理过,可以把
s
d
o
m
sdom
sdom的初值设为它们自己、
通过定理4可以求出所有点的
s
d
o
m
sdom
sdom。
接下来将它挂在它的
s
d
o
m
sdom
sdom上。每做完一个子树之后,在并查集上将子树和父亲合并,然后处理留在父亲上的
s
d
o
m
sdom
sdom,也就是通过引理1来计算
i
d
o
m
idom
idom。具体来说,如果父亲是
x
x
x,挂在父亲上的点
w
w
w,它们满足
s
d
o
m
(
w
)
=
x
sdom(w)=x
sdom(w)=x,如果
s
d
o
m
(
e
v
a
l
(
w
)
)
=
x
sdom(eval(w))=x
sdom(eval(w))=x,那么
i
d
o
m
(
w
)
=
s
d
o
m
(
w
)
=
x
idom(w)=sdom(w)=x
idom(w)=sdom(w)=x,否则
i
d
o
m
(
w
)
=
i
d
o
m
(
e
v
a
l
(
w
)
)
idom(w)=idom(eval(w))
idom(w)=idom(eval(w)),这个东西先不要求出来,可以在实现的时候记作
i
d
o
m
(
w
)
=
e
v
a
l
(
w
)
idom(w)=eval(w)
idom(w)=eval(w)。
最后就是第4步,按照
d
f
n
dfn
dfn从小到大枚举,如果
i
d
o
m
(
w
)
=
s
d
o
m
(
w
)
idom(w)=sdom(w)
idom(w)=sdom(w),说明
i
d
o
m
(
w
)
idom(w)
idom(w)已经被处理过,不理它;否则,
i
d
o
m
(
x
)
=
i
d
o
m
(
i
d
o
m
(
x
)
)
idom(x)=idom(idom(x))
idom(x)=idom(idom(x))。
这样就求出所有点的
i
d
o
m
(
x
)
idom(x)
idom(x)了。
清点一下要维护的东西:
i
d
o
m
idom
idom和
s
d
o
m
sdom
sdom数组
并查集维护
e
v
a
l
eval
eval
每个点的前驱
p
r
e
d
pred
pred
将点挂在
s
d
o
m
sdom
sdom用的数组(链表)
b
u
c
buc
buc
以及一些零零散散的东西。
这个算法的时间复杂度实际上是
O
(
n
lg
n
)
O(n \lg n)
O(nlgn)的,我受到了那篇博客的影响,知道并查集能被卡成
lg
\lg
lg级别。当然这种情况大多数是不会见到的,毕竟没几个人来卡你的并查集,就算卡,凭借着并查集的优秀常数也不会多慢。
姑且认为是
O
(
n
α
(
n
)
)
O(n \alpha(n))
O(nα(n))的,几乎都是这样了。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200000
#define M 300000
int n,m;
struct EDGE{
int to;
EDGE *las;
} e[M+1],pe[M+1],te[M+1],be[M+1];
//这四个东西都用链表来存。e表示图边,pe表示反向边(pred),te表示建出来的支配树,be表示buc
int ne,pne,tne,bne;
EDGE *last[N+1],*plast[N+1],*tlast[N+1],*blast[N+1];
int dfn[N+1],nowdfn,ver[N+1]; //dfn为dfs的时间戳,ver为dfs序。
int idom[N+1],sdom[N+1];
int fa[N+1];
void init(int x){//初始化,求出dfn,ver
dfn[x]=++nowdfn,ver[nowdfn]=x;
sdom[x]=x;
for (EDGE *ei=last[x];ei;ei=ei->las)
if (!dfn[ei->to]){
fa[ei->to]=x;
init(ei->to);
}
}
int top[N+1],eval[N+1];//这些就是并查集维护的东西
inline int sdom_min(int a,int b){return dfn[sdom[a]]<dfn[sdom[b]]?a:b;}
inline int dfn_min(int a,int b){return dfn[a]<dfn[b]?a:b;}
void gettop(int x){
if (top[x]==x)
return;
gettop(top[x]);
eval[x]=sdom_min(eval[x],eval[top[x]]);
top[x]=top[top[x]];
}
int siz[N+1];//最后的答案(洛谷的模板题输出支配树中每个点的子树大小)
void get_siz(int x){
siz[x]=1;
for (EDGE *ei=tlast[x];ei;ei=ei->las)
get_siz(ei->to),siz[x]+=siz[ei->to];
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i){
int u,v;
scanf("%d%d",&u,&v);
e[++ne]={v,last[u]};
last[u]=e+ne;
pe[++pne]={u,plast[v]};
plast[v]=pe+pne;
}
init(1);
for (int i=1;i<=n;++i)
top[i]=eval[i]=i;
for (int i=n;i>=1;--i){
int x=ver[i],y=fa[x];
for (EDGE *ei=plast[x];ei;ei=ei->las)
gettop(ei->to),sdom[x]=dfn_min(sdom[x],sdom[eval[ei->to]]);//枚举前缀计算sdom
be[++bne]={x,blast[sdom[x]]};//将x挂到sdom[x]上
blast[sdom[x]]=be+bne;
if (y)
for (top[x]=y;blast[y];blast[y]=blast[y]->las){//将自己的子树和父亲合并;清空挂在父亲上的点,用来求idom
int v=blast[y]->to;
gettop(v);
if (sdom[eval[v]]==sdom[v])
idom[v]=sdom[v];
else
idom[v]=eval[v];
}
}
for (int i=1,x=ver[i];i<=n;++i,x=ver[i])//将没有计算完idom的点计算好
if (idom[x]!=sdom[x])
idom[x]=idom[idom[x]];
for (int i=2;i<=n;++i){
te[++tne]={i,tlast[idom[i]]};
tlast[idom[i]]=te+tne;
}
get_siz(1);
for (int i=1;i<=n;++i)
printf("%d ",siz[i]);
return 0;
}