LCA Tarjan演算法理解

2021-06-28 13:51:39 字數 2753 閱讀 6862

scturtleposted @ 2023年10月08日 11:08 in 

algorithm , 2734 閱讀

tarjan演算法的步驟是(當dfs到節點u時):

1 在並查集中建立僅有u的集合,設定該集合的祖先為u

1 對u的每個孩子v:

1.1 tarjan之

1.2 合併v到父節點u的集合,確保集合的祖先是u

2 設定u為已遍歷

3 處理關於u的查詢,若查詢(u,v)中的v已遍歷過,則lca(u,v)=v所在的集合的祖先

舉例說明(非證明):

假設遍歷完10的孩子,要處理關於10的請求了

取根節點到當前正在遍歷的節點的路徑為關鍵路徑,即1-3-8-10

集合的祖先便是關鍵路徑上距離集合最近的點

比如此時:

1,2,5,6為乙個集合,祖先為1,集合中點和10的lca為1

3,7為乙個集合,祖先為3,集合中點和10的lca為3

8,9,11為乙個集合,祖先為8,集合中點和10的lca為8

10,12為乙個集合,祖先為10,集合中點和10的lca為10

你看,集合的祖先便是lca吧,所以第3步是正確的

道理很簡單,lca(u,v)便是根至u的路徑上到節點v最近的點

為什麼要用祖先而且每次合併集合後都要確保集合的祖先正確呢?

因為集合是用並查集實現的,為了提高速度,當然要平衡加路徑壓縮了,所以合併後誰是根就不確定了,所以要始終保持集合的根的祖先是正確的

關於查詢和遍歷孩子的順序:

wikipedia上就是上文中的順序,很多人的**也是這個順序

但是網上的很多講解卻是查詢在前,遍歷孩子在後,對比上文,會不會漏掉u和u的子孫之間的查詢呢?

不會的如果在剛dfs到u的時候就設定u為visited的話,本該回溯到u時解決的那些查詢,在遍歷孩子時就會解決掉了

這個順序問題就是導致我頭大看了很久這個演算法的原因,也是絮絮叨叨寫了本文的原因,希望沒有理解錯= =

最後,為了符合本blog風格,還是貼**吧:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

intf[maxn],fs[maxn];//並查集父節點 父節點個數

boolvit[maxn];

intanc[maxn];//祖先

vector<int> son[maxn];//儲存樹

vector<int> qes[maxn];//儲存查詢

typedefvector<int>::iterator it;

intfind(intx)

voidunion(intx,inty)

voidlca(intu)

vit[u]=true;

for(it v=qes[u].begin();v!=qes[u].end();++v)

}

ref:

A 演算法理解

廣度優先 bfs 和深度優先 dfs 搜尋 深度優先搜尋,用俗話說就是不見棺材不回頭。演算法會朝乙個方向進發,直到遇到邊界或者障礙物,才回溯。一般在實現的時候,我們採用遞迴的方式來進行,也可以採用模擬壓棧的方式來實現。如下圖,s代表起點,e代表終點。我們如果按照右 下 左 上這樣的擴充套件順序的話,...

dijkstra 演算法理解

求有向圖中乙個源點到其他頂點的最短距離 自己的理解 剛開始的時候相當於有三個集合 v 頂點集合 s 已求得的最短距離頂點集合,假設求a到其他頂點的最短距離 s 剩餘頂點集合 d 儲存的是最短距離值 求一維陣列中的最小值的下標,這個陣列不包含已經求得的頂點 找出最小值下標後,放入到s中,然後求剩餘頂點...

KM演算法理解

二分圖帶權匹配與最佳匹配 什麼是二分圖的帶權匹配?二分圖的帶權匹配就是求出乙個匹配集合,使得集合中邊的權值之和最大或最小。而二分圖的最佳匹配則一定為完備匹配,在此基礎上,才要求匹配的邊權值之和最大或最小。二分圖的帶權匹配與最佳匹配不等價,也不互相包含。我們可以使用km演算法實現求二分圖的最佳匹配。方...