最近公共祖先(LCA)

2022-07-15 04:48:06 字數 1985 閱讀 8088

採用兩點逐漸向根移動的方法,求出lca。

具體步驟:

1.求出每個節點的深度

2.詢問兩個節點是否重合,若重合,則lca已經求出。否則,選擇兩個點中深度較大乙個,移動它的父親。

時間複雜度\(o(n)\),查詢\(q\)次的話,複雜度\(o(qn)\)

優點:簡單,該演算法允許樹動態改變。

**如下:

struct edgee[maxn];

void addedge(int u,int v)

//建樹的過程

//同時求出每個節點的深度,與每個節點的父親

void dfs(int u,int father)

return ;

}//相當於模擬移動

int lca(int u,int v)

return u;

}int main()

dfs(s,s);

for(int i=1;i<=m;++i)

return 0;

}

第一步:初始化(建樹)

求出倍增陣列 \(anc\)。(和一開始建樹的思路一樣)

其中,maxlog是最小的滿足\(2^x \leq maxdeep\)(最深的節點深度)的\(x\)。

\(anc[i][j]\)為\(i\)節點向上走\(2^j\)後能走到的點。

我們規定根節點的父親就是它自己,這樣根節點往上走還是根節點。

對於\(anc\) 而言,有如下的遞推關係:

\(anc[i][j]=\left\

anc[i][j] & j=0 \\

anc[anc[i][j-1]][j-1]& j> 1

\end\right.

\)解釋:

第乙個,\(j=0\)就是根節點。

第二個,從\(anc\)的意義出發:節點\(i\)向上走\(2^\)步後,再走\(2^\)步,加起來就是\(2^j\)次步。

第二步:把兩個節點移動到同一深度

假設\(lca(x,y)\)不失一般性,令\(deep[x] /leq deep[y]\)。

先讓x往上走\(deep[x]-deep[y]\)步。

我們將這個差值轉化為二進位制,然後,通過通過倍增陣列往上走\(2\)的冪次步。

(即:對於二進位制為\(1\)的第\(i\)位,往上走\(2^i\)步)

或者,還有一種方法:

從大到小掃瞄\(i\),如果\(anc[x][i]\)的深度不小於\(y\),就跳\(x\)。

第三步: 求lca

在第二步的處理後,假設\(x,y\)往上走最小的\(l\)步後是同一節點,也就意味著,\(x,y\)向上走最大的\(l-1\)步,是不同的節點。

我們可以從大到小的列舉\(2^i\)步,如果當前\(x,y\)向上走\(2^i\)步後為同一點,則停止。否則就一起往上走。

(由於倍增陣列的特性,該過程可以看成二分)

直到不能走為止,再往上走一步就是\(lca\)。(ps:\(2^0=1\))

時間複雜度:\(o((n+q)log_2(n))\)

**如下:

#include #define maxn 10000005

#define maxlog 32

using namespace std;

int n,m,s;

int deep[maxn],anc[maxn][maxlog];

int cnt=0,adj[maxn];

struct edge

e[maxn];

void addedge(int u,int v)

void dfs(int u,int father)

}return anc[u][0];

}int main()

dfs(s,s);

for(int i=1;i<=m;++i)

return 0;

}

最近公共祖先 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的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...