LCA


方法
(1)向上標記法O(n)
這個方法很暴力,沒什么說的,如果有m次查詢,那時間復雜度就會是O(nm)
(2)倍增
步驟:
1.初始化:通過dfs初始化兩個數組depth[],fa[i,j];
depth[i]:表示深度
fa[i,j]:表示從i開始,向上走\(2^j\)步所能走到的節點編號(\(0 \leq j \leq logn\))
哨兵:如果從i開始跳\(2^j\)步會跳過根節點,那么fa[i,j]=0,depth[0]=0;
2.查詢
[1]現將兩個點同時調到同一層
[2]讓兩個點同時往上跳,一直跳到它們的最近公共祖先的下一層
預處理 O(nlogn)
查詢O(logn)
具體代碼實現可以看這里 AcWing1172.祖孫詢問
(3)Tarjan——離線求LCA O(n+m)
在優先遍歷時,將所有點分為三大類:
[0] 還未搜索過的點
[1] 正在搜索的分支
[2] 已經遍歷過,且回溯過的點。
QQ圖片20210809221551.png

步驟:
1.在進入遞歸層時,將點標記為1
2.搜索所有沒有遍歷過的鏈接且與該點鏈接的點,搜索回溯后,完成集合合並
3.將所有與該層點有關系的詢問,全部遍歷,當另一個點已經被標記為2,則找到了最近公共祖先,就是另一個點的並查集標志節點。
4.最后回溯時,將該節點標記為2.

注意:
一定要先將要拓展的點進行拓展,回溯時再進行集合合並。記憶的話,就記住,我們進行集合合並的點一定是被回溯過的。理解的話,可以看這個例子。
比如正在遍歷的一條路徑上a->b->c->d剛遍歷完c節點的子樹並回溯到c節點
那么假如有一個詢問是在c-d節點之間,對於d節點st[d]=2;
如果p[j]=u,那么p[a]=a,p[b]=a,p[c]=b那么進行anc=find(d)操作時會把d的祖先p[d]直接路徑壓縮成a節點。
如果p[j]=u,由於p[c]=c,那么在進行anc=find(d)操作時p[d]c節點
顯然,我們要找的是最近公共祖先,那就要先遍歷再合並。
其實就是,如果我們提前進行合並那同一路上的公共祖先就會出現問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM