LCA(最近公共祖先)

2022-05-06 15:33:13 字數 1916 閱讀 4976

求lca的方法有很多,在這裡就只介紹一種離線演算法,tarjan演算法! 可以保證在o(n+q)的時間複雜度內算出所有答案(n是節點個數  q是詢問個數)

為什麼叫離線演算法呢?  因為這種演算法的思想是先把所有的詢問存起來,在遍歷的樹的同時遍歷這顆子樹包含的詢問:

本演算法結合了深度優先搜尋(dfs)和並查集的思想,下面說一下大體流程:

同時處理有關當前節點的詢問,如果有乙個當前節點到節點v的詢問,且被檢查過,則由於進行的是深度優先搜尋,當前節點與v的最近公共祖先一定還沒有被檢查過,而這個最近公共祖先的包含v的子樹

一定已經搜尋過了,那麼這個最近公共祖先一定是v集合所在集合的祖先。

如圖:根據實現演算法可以看出,只有當某一棵子樹全部遍歷處理完成後,才將該子樹的根節點標記為黑色(初始化是白色),假設程式按上面的樹形結構進行遍歷,首先從節點1開始,然後遞迴處理根為2的子樹,當子樹2處理完畢後,節點2, 5, 6均為黑色;接著要回溯處理3子樹,首先被染黑的是節點7(因為節點7作為葉子不用深搜,直接處理),接著節點7就會檢視所有詢問(7, x)的節點對,假如存在(7, 5),因為節點5已經被染黑,所以就可以斷定(7, 5)的最近公共祖先就是find(5).ancestor,即節點1(因為2子樹處理完畢後,子樹2和節點1進行了union,find(5)返回了合併後的樹的根1,此時樹根的ancestor的值就是1)。有人會問如果沒有(7, 5),而是有(5, 7)詢問對怎麼處理呢? 我們可以在程式初始化的時候做個技巧,將詢問對(a, b)和(b, a)全部儲存,這樣就能保證完整性。

**分為六塊:

1、輸入樹:只需要存x->y有一條邊 並不需要存雙向邊,因為是從根節點開始走的  (也就是入度為0的點) 同時找到根節點

2、輸入詢問:注意如果查詢u v的最近公共祖先   v u也存進去  (上面已經說明了原因)

3、初始化並查集

4、初始化所有點的祖先

5、初始化所有點都沒有被檢查過

6、tarjan演算法:其實就是深搜 再把搜完的子樹和當前節點合併為乙個集合   祖先是當前節點。  當搜尋完所有的子樹之後   標記當前節點為訪問過   並查詢所有與當前節點有關的詢問。。

#include#include

#include

#include

#include

using

namespace

std;

const

int maxn=10000;//

最大頂點數

int n,root;//

實際頂點數 樹根節點

int indeg[maxn];//

頂點入度 用來判斷樹根

vector tree[maxn];//

樹的鄰接表(不一定是二叉樹)

void

inputtree()

for(int i=0;i//

尋找樹根 入度為0的點

}}vector

query[maxn];//

所有查詢內容

void inputquires()//

輸入查詢

}int father[maxn],rnk[maxn];//

節點的父親 秩

void makeset()//

初始化並查集

}int findset(int x)//

查詢祖先

void unionset(int x,int y)//合併}

int ancestor[maxn];//

已經訪問節點集合的祖先

bool vs[maxn];//

訪問標記

void tarjan(int x)//

tarjan演算法求解lca

vs[x]=1;//

標記為訪問過

for(int i=0;i//

與根節點有關的查詢

}int

main()

最近公共祖先 LCA 最近公共祖先

直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...

最近公共祖先 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...

LCA 最近公共祖先

定義 對於有根樹t的兩個結點u v,最近公共祖先lca t,u,v 表示乙個結點x,滿足x是u v的祖先且x的深度盡可能大。另一種理解方式是把t理解為乙個無向無環圖,而lca t,u,v 即u到v的最短路上深度最小的點。現在給定乙個根為1的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...