1. 程式人生 > >LCA離線算法Tarjan詳解

LCA離線算法Tarjan詳解

lca class 初始化 連通 一個 ans 為什麽 原理 子節點

離線算法也就是需要先把所有查詢給保存下來,最後一次輸出結果。

離線算法是基於並查集實現的,首先就是初始化P[i] = i。

接下來對於每個點進行dfs:

①首先判斷是否有與該點有關的查詢,如果當前該點為u,與它有關的點為v,如果v已經訪問過了,那麽它們的LCA就是find(v)。如果v還沒有訪問,那就不用管它。

②對該點的子節點繼續dfs,需要註意的是,dfs完之後需要需要p[v]=u,將v點並到其父親節點上。

 1 void LCA(int u)
 2 {
 3     vis[u]=1;
 4     for(int i=qhead[u];i!=-1;i=query[i].next)
5 { 6 int v=query[i].v; 7 if(vis[v] && !mark[Find(v)]) //mark數組是為了針對非連通圖的情況 8 ans[query[i].index]=Find(v); //index次詢問的公共祖先為Find(v) 9 } 10 11 for(int i=ehead[u];i!=-1;i=e[i].next) 12 { 13 int v=e[i].v; 14 if(!vis[v]) 15 {
17 LCA(v); 18 p[v]=u; 19 } 20 } 21 }

接下來詳細解釋一下為什麽是這麽一個原理:

對於任意兩個節點u和v來說,它們只有兩種關系:①子節點關系;②非子節點關系。

①子節點關系

技術分享

u和v的公共祖先很明顯的就是u,在訪問u結點的時候,v節點還沒有被訪問,此時繼續訪問u的子節點。那麽當訪問到v節點的時候,因為u節點已經被訪問,所以此時u、v的LCA=find(u),由於此時p[u]=u,所以此時它們的LCA就是u。

②非子節點關系

技術分享

此時u和v兩個節點肯定有一個先訪問,另一個後訪問,現在就假設u先訪問(v先訪問的情況也是一樣的)。

訪問到u時,v還沒有被訪問,所以此時不用管,繼續訪問u的子節點,當u的子節點訪問完之後,p[u] = f。

接下來訪問到v時,由於u已經被訪問,所以它們的LCA就是find(u),也就是p[f]=f,因為此時f的子節點還沒有訪問完,所以p[f]是不變的。

好了,兩種情況都證明了。

LCA離線算法Tarjan詳解