LG5180[模板]支配樹【Lengauer-Tarjan算法】
LG5180[模板]支配樹【Lengauer-Tarjan算法】
轉載自https://www.luogu.org/problemnew/solution/P5180
來一個$Tarjan$老爺子的$Lengauer-Tarjan$算法吧
最優是$O(nα(n))$ 但是會被卡成$O(nlogn)$
(這裏默認nm數量級同階)
1.定義
對於一棵可以存在環的有向圖
給定一個起點$r$ 對於一個終點$x$ 如果$r$到達$x$的所有路徑都會經過一個點$y$
那麽我們就稱之為$y$支配$x$
我們令支配$x$的點集為$S=p_1,p_2,p_3,......,p_k$
那麽從起點$r$到達$x$的任意一條路徑排列為$r......p_1......p_2......p_k...x$
支配樹可以對於每一個點$x(x!=r)$求出$p_k$ 也就是點集$S$當中距離$x$最近的支配點
這個點我們稱之為$idom[x]$
如果每一個點連出指向$idom[x]$ 那麽就構成了一顆內向樹 我們稱之為支配樹
2.算法
1.首先我們需要一顆$DFS$樹
也就是對這個算法進行$dfs$遍歷 求出其$dfs$序
2.半必經點
從$y$出發到$x$ 存在這樣一條路徑 路徑上的點(不包括$x$以及$y$)的$dfn$均大於$dfn[x]$ 我們稱$y$是$x$的半必經點
$sdom[x]$表示$x$的半必經點中$dfn$最小的點
為什麽要求這個點呢 ? ? ? 我們刪掉原圖中的非樹邊 然後連接$(sdom[x],x)$ 不改變原圖中的支配點關系
這樣的話 我們就把原圖變為了一個$DAG$ 就可以使用$DAG$的做法了 但是還有更優的方法
求半支配點
對於一個點$x$ 找出所有的邊$(y,x)$中對應的$y$
若$dfn[y] < dfn[x]$且$dfn[y]$比當前找到的$sdom[x]$的$dfn$小 那麽就用$sdom[x]=y$
若$dfn[y]>dfn[x]$ 找到樹上$y$的一個祖先$z$ 並且$dfn[z]>dfn[x]$ 比較$dfn[sdom[z]]$同$dfn[sdom[x]]$ 決定是否用前者更新後者
從半支配點到支配點
對於$x$ 我們要的是$idom[x]$
尋找方法如下
我們令$P$是從$sdom[x]$到$x$的樹上路徑點集(不包括$sdom[x]$) 而且$z$是$P$中$dfn[sdom[z]]$最小的點
如果$sdom[z]=sdom[x]$ 那麽$idom[x]=sdom[x]$ 否則就是$idom[x]=idom[z]$
算法流程
我們用帶權並查集來實現
首先按照$dfs$序從大到小處理 每一次處理完畢一個點之後 將這個點同其在$dfs$樹上的父親在並查集連邊
而並查集的權 就是並查集這個點到根節點的路徑上的所有點 最小的$dfn[sdom[x]]$對應的$x$
找$sdom[]$直接找即可 找$idom$可以使用$sdom[x]$處理
LG5180[模板]支配樹【Lengauer-Tarjan算法】