支配树学习

看某个ppt的时候看到了这个东西,就产生了一些兴趣。
这个东西似乎有点鸡肋,我做了这么久的题,没有见过一道是用支配树解决的。
不过这个算法真的很有趣。
现在我还没有学完。打打博客加深理解。
先推荐一篇很好的博客


什么是支配树?

现在我给你一个起点为r rr的有向图,你需要求各种有关必经点的问题。
先说一堆概念:
支配点对于一个点x xx,如果r rrx xx的所有路径上经过y yy,那么y yy支配x xx
最近支配点对于一个点x xx,如果有一个点y yy满足y yy支配x xx,并且所有支配x xx的平凡支配点全都支配y yy,那么y yy就是x xx的最近必经点,记作i d o m ( x ) idom(x)idom(x)
平凡支配点就是除了x xx,之外的所有支配点。(其实网上的其它博客说r rr也不包括在内,不过我觉得这样方便理解)

定理1:对于任意的点,它的最近支配点都是唯一的。

证明:假设这个点是x xx,它有两个最近支配点分别为y yyz zz
由定义得z zz支配y yy,并且y yy支配z zz
因为y ≠ z y\neq zy̸=z,所以矛盾

这个证明是不是特别简略……

既然每个点的最近支配点都是唯一的,那我们自然而然地想到可以建立一棵树。
对于点x xx,将i d o m ( x ) idom(x)idom(x)作为自己的父亲,方向为i d o m ( x ) idom(x)idom(x)x xx
这就是支配树。

性质?

对于一个点x xx,所有支配它的点都是它在支配树上的祖先。
所以说我们可以利用它这个奇妙的性质做各种各样有关必经点的事情。

知道了支配树的功能,现在我们的主要问题是,如何建立支配树。
建立支配树就需要更多的概念和性质……


更加详细的性质

首先,从r rr开始,建立一棵dfs树
显然这个dfs树并不是支配树……
记录一下它们的dfs序,在后面的叙述中,我直接用dfs序来表示它们的编号。

一棵图中的边( x , y ) (x,y)(x,y)有四种情况:树枝边(这里指的是dfs树),前向边(x xxy yy的祖先),后向边(x xxy yy的后代),横插边(显然x > y x>yx>y)。
接下来我们用几个符号来表示各种关系(这个一定要记住):
a → b a\to bab表示a aa能直接通过一条边到达b bb
a ⇝ b a \leadsto bab表示a aa能通过某条路径到达b bb
a → ˙ b a \dot \to ba˙b表示a aa能通过树枝边到达b bb
a → + b a \overset{+}{\to}ba+b表示a → ˙ b a \dot \to ba˙b并且a ≠ b a\neq ba̸=b

引理1(路径引理)
对于两个点v vvw ww,若v ≤ w v\leq wvw,那么v vvw ww的路径上必定经过他们的公共祖先(也就是L C A ( v , w ) LCA(v,w)LCA(v,w)及其所有祖先)

证明:如果v vvw ww的祖先,显然成立。
因为横插边都是从大点去到小点,所以不可以通过横插边从v vv所在的子树到达w ww所在的子树。
所以只能通过后向边跳上公共祖先,然后从公共祖先通过前向边跳下来。

半支配点

对于w ≠ r w\neq rw̸=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,,vk1,vk),v0=v,vk=w,1ik1,vi>w}
也就是说,从s d o m ( w ) sdom(w)sdom(w)开始,存在一条从s d o m ( w ) sdom(w)sdom(w)w ww的路径,使得中间经过的所有点都比w ww大。
注意,半支配点并不一定是支配点,可能是支配点。


引理2
对于任意w ≠ r w\neq rw̸=r,满足i d o m ( w ) → + w idom(w) \overset{+}{\to} widom(w)+w
(证明显然:如果不是这样,它就可以直接通过树枝边来到达w ww了,与定义矛盾)

引理3
对于任意w ≠ r w\neq rw̸=r,满足s d o m ( w ) → + w sdom(w) \overset{+}{\to} wsdom(w)+w

证明:首先,f a w fa_wfaws d o m ( w ) sdom(w)sdom(w)的一个候选,因为中间没有任何的点落脚。
所以s d o m ( w ) ≤ f a w sdom(w)\leq fa_wsdom(w)faw
根据路径引理,如果s d o m ( w ) sdom(w)sdom(w)在另一棵子树,那么必定经过他们的公共祖先,公共祖先小于x xx,与定义矛盾

引理4
对于任意w ≠ r w \neq rw̸=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 wrsdom(w)w
s d o m ( w ) ⇝ w sdom(w)\leadsto wsdom(w)w不经过i d o m ( w ) idom(w)idom(w),与i d o m idomidom的定义矛盾

引理5
对于满足v → ˙ w v \dot \to wv˙w的点v vvw wwv → ˙ 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}widom(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 widom(w)˙idom(v)+v˙w
也就是i d o m ( v ) → + v idom(v)\overset{+}{\to}vidom(v)+v要么被i d o m ( w ) → + w idom(w)\overset{+}{\to}widom(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} widom(v)+idom(w)+v+w
存在r → ˙ i d o m ( v ) ⇝ v → + w r \dot \to idom(v) \leadsto v \overset{+}{\to} wr˙idom(v)v+w。(i d o m ( w ) idom(w)idom(w)i d o m ( v ) idom(v)idom(v)的真后代,不支配v vv。所以可以绕过i d o m ( w ) idom(w)idom(w)到达w ww
i d o m idomidom的定义矛盾。


这后面的会难一些,不对,是难很多。
揭示了i d o m idomidoms d o m sdomsdom的关系
定理2
对于任意w ≠ r w\neq rw̸=r,如果所有满足s d o m ( w ) → + u → ˙ w sdom(w)\overset{+}{\to}u\dot \to wsdom(w)+u˙wu uu也满足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 wsdom(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 ww即可。
对于任意从r rrw ww的路径,取最后一个小于s d o m ( w ) sdom(w)sdom(w)的点x xx
假设y yyx xx的后继
由于x xx是最后一个小于s d o m ( w ) sdom(w)sdom(w)的点,所以s d o m ( w ) ≤ y sdom(w) \leq ysdom(w)y
s d o m sdomsdom的定义得,必定存在y yy满足s d o m ( w ) → ˙ y → ˙ w sdom(w)\dot \to y \dot \to wsdom(w)˙y˙w(否则x xx就是s d o m ( w ) sdom(w)sdom(w)
取最小的y yy,假设y yy不是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 &lt; s d o m ( w ) x&lt; 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} yx+t+y,由于x xx是最后一个小于s d o m ( w ) sdom(w)sdom(w)的点,所以s d o m ( w ) → ˙ t → ˙ w sdom(w)\dot \to t \dot \to wsdom(w)˙t˙w
在前面已经说过y yy是最小的,所以矛盾
因此y yy就是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 ww
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 ww
反证法,假设存在路径绕过s d o m ( w ) sdom(w)sdom(w)到达w ww
这条路径必定可以看作,从r rr绕过s d o m ( w ) sdom(w)sdom(w)到达点x xx(满足s d o m ( w ) → + x → ˙ w sdom(w)\overset{+}{\to}x \dot \to wsdom(w)+x˙w),然后直接到w ww
1、当从某个比x xx大的点来到x xx时,由于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 rr到达s d o m ( x ) sdom(x)sdom(x),不存在这样的路径。
2、当从某个比x xx小的点来到w ww时,
(1)如果从树枝边走来:
如果x xxs 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 ww之间的路径上。
(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 rw̸=r,设u uu为满足s d o m ( w ) → + u → ˙ w sdom(w) \overset{+}{\to} u \dot \to wsdom(w)+u˙ws d o m ( u ) sdom(u)sdom(u)最小的u uu,如果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 wsdom(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 44得后面的这种情况不存在。
画张图理解一下: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 widom(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 ww即可。
类似于之前的思路:
假设有某一条路径绕过i d o m ( u ) idom(u)idom(u)到达w ww
1、从大于w ww点到达w ww
如果这样,存在一个点x xx,满足s d o m ( w ) sdom(w)sdom(w)的定义(不一定最小)。
如果x → + u x \overset{+}{\to} ux+u
因为i d o m ( u ) idom(u)idom(u)支配u uu,而又存在r ⇝ x → + u r \leadsto x \overset{+}{\to} urx+u,所以i d o m ( u ) idom(u)idom(u)支配x xx
所以不存在某种绕过s d o m ( w ) sdom(w)sdom(w)到达x xx的方案。
如果u → ˙ x u\dot \to xu˙x,那么继续考虑能不能到达x xx(像个递归的过程),最终总会到x → + u x\overset{+}{\to} ux+u的状况,因此也是不存在的。
2、从小于w ww点到达w ww
(1)从树枝边走来
类似于之前的情况,如果存在这样的路径,必定能从起点绕过i d o m ( u ) idom(u)idom(u)到达u uuw ww之间的某个点。(前面已经证明过绕i d o m ( u ) idom(u)idom(u)到达i d o m ( u ) idom(u)idom(u)u uu之间的点不存在)
但是连s d o m ( u ) sdom(u)sdom(u)最小的u uu都不成立,那其他的点也不可能了。
(2)从i d o m ( u ) idom(u)idom(u)外走来
如果可以这么走,那它就应该是s d o m ( w ) sdom(w)sdom(w),矛盾。
综上所述,不存在这样的路径


推论1
对于任意r ≠ w r\neq wr̸=w,如果有满足s d o m ( w ) → + u → ˙ w sdom(w) \overset{+}{\to} u \dot \to wsdom(w)+u˙ws d o m ( u ) sdom(u)sdom(u)最小的u uu,那么
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 ) &lt; s d o m ( w ) ) idom(w) = \left \{ \begin{aligned}&amp; sdom(w)&amp;(sdom(u)=sdom(w))&amp;\\ &amp;idom(u)&amp;(sdom(u)&lt;sdom(w))&amp;\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 ) &gt; s d o m ( w ) sdom(u)&gt;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 wsdom(w)+sdom(u)+u˙w
显然s d o m ( s d o m ( u ) ) &lt; s d o m ( u ) sdom(sdom(u))&lt;sdom(u)sdom(sdom(u))<sdom(u),所以此时的s d o m ( u ) sdom(u)sdom(u)应该是u uu
我们已经要求过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 sdomsdom则太慢,于是就有了下面这个强大的定理:
定理4
对于任意w ≠ r w\neq rw̸=rs d o m ( w ) = m i n ( { v ∣ ( v , w ) ∈ E , v &lt; w } ∪ { s d o m ( u ) ∣ u &gt; w , ∃ ( v , w ) ∈ E , u → ˙ v } ) sdom(w) = min(\{v | (v, w) \in E , v &lt; w \} \cup \{sdom(u) | u &gt; 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 xx,显然s d o m ( w ) ≤ x sdom(w)\leq xsdom(w)x。现在要证明x ≤ s d o m ( w ) x\leq sdom(w)xsdom(w)
如果s d o m ( w ) sdom(w)sdom(w)w ww中只经过一条边,显然( s d o m ( w ) , w ) ∈ E (sdom(w),w)\in E(sdom(w),w)Es d o m ( w ) &lt; w sdom(w)&lt;wsdom(w)<w,所以x ≤ s d o m ( w ) x\leq sdom(w)xsdom(w)
如果不只经过一条边,设这条路径上的最后一个点为l a s t lastlast。在s d o m ( w ) sdom(w)sdom(w)l a s t lastlast之间找到一个最小的点p pp,显然s d o m ( w ) sdom(w)sdom(w)p pp上经过的点都比p pp大,所以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 lastp˙last( l a s t , w ) ∈ E (last,w)\in E(last,w)E
所以s d o m ( p ) sdom(p)sdom(p)x xx的一个候选,所以x ≤ s d o m ( p ) ≤ s d o m ( w ) x\leq sdom(p)\leq sdom(w)xsdom(p)sdom(w),所以x ≤ s d o m ( w ) x \leq sdom(w)xsdom(w)
综上,x ≤ s d o m ( w ) x\leq sdom(w)xsdom(w)
所以s d o m ( w ) = x sdom(w)=xsdom(w)=x


Lengauer-Tarjan算法

前面推的东西都是为这个算法铺垫的。这个算法用到定理4和推论1。
先说说步骤:
1、dfs一遍,求出d f n dfndfn
2、按照d f n dfndfn倒着求出s d o m sdomsdom
3、确定i d o m = s d o m idom=sdomidom=sdomi d o m idomidom,其它的暂时不理它。
4、按照d f n dfndfn顺着找没有计算的i d o m idomidom,计算。

第1步不说。
第2步和第3步可以放在一起来写。
我们要用一个数据结构来维护一个森林,每个点到根的路径上最小的s d o m sdomsdom。这个数据结构可以用并查集。我们记作x xx的这个东西为e v a l ( x ) eval(x)eval(x)
看看定理4的式子:s d o m ( w ) = m i n ( { v ∣ ( v , w ) ∈ E , v &lt; w } ∪ { s d o m ( u ) ∣ u &gt; w , ∃ ( v , w ) ∈ E , u → ˙ v } ) sdom(w) = min(\{v | (v, w) \in E , v &lt; w \} \cup \{sdom(u) | u &gt; 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 ww来说,若它的前驱v &gt; w v&gt;wv>w,那么上式右边的u uue v a l ( v ) eval(v)eval(v)是最合适的。如果前驱v &lt; w v&lt;wv<w,它们没有处理过,可以把s d o m sdomsdom的初值设为它们自己、
通过定理4可以求出所有点的s d o m sdomsdom
接下来将它挂在它的s d o m sdomsdom上。每做完一个子树之后,在并查集上将子树和父亲合并,然后处理留在父亲上的s d o m sdomsdom,也就是通过引理1来计算i d o m idomidom。具体来说,如果父亲是x xx,挂在父亲上的点w ww,它们满足s d o m ( w ) = x sdom(w)=xsdom(w)=x,如果s d o m ( e v a l ( w ) ) = x sdom(eval(w))=xsdom(eval(w))=x,那么i d o m ( w ) = s d o m ( w ) = x idom(w)=sdom(w)=xidom(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 dfndfn从小到大枚举,如果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 idomidoms d o m sdomsdom数组
并查集维护e v a l evaleval
每个点的前驱p r e d predpred
将点挂在s d o m sdomsdom用的数组(链表)b u c bucbuc
以及一些零零散散的东西。

这个算法的时间复杂度实际上是O ( n lg ⁡ n ) O(n \lg n)O(nlgn)的,我受到了那篇博客的影响,知道并查集能被卡成lg ⁡ \lglg级别。当然这种情况大多数是不会见到的,毕竟没几个人来卡你的并查集,就算卡,凭借着并查集的优秀常数也不会多慢。
姑且认为是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;
}

版权声明:本文为A1847225889原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。