最近公共祖先 LCA

2022-07-11 18:12:14 字數 1955 閱讀 7996

這幾年\(noip\)考樹考的好多,打算寫幾篇部落格來增強記憶。\(noip rp++\)

在樹上的問題中,對兩個點展開的有很多,\(lca\)在很多時候會起到很大的作用。

首先我們要談談什麼是最近公共祖先:對於有根樹\(t\)的兩個結點\(u、v\),最近公共祖先\(lca(t,u,v)\)表示乙個結點\(x\),滿足\(x\)是\(u\)和\(v\)的祖先且\(x\)的深度盡可能大。在這裡,乙個節點也可以是它自己的祖先。也可以理解為距離兩個節點最近的公共祖先。所以它主要是用來處理當兩個點有唯一一條確定的最短路徑時的路徑。這裡我們就不介紹其他一些演算法了,只談倍增的方法。

首先我們來理解一下什麼是倍增,倍增就是按照\(2\)的倍數來增長,\(1, 2, 4, 8, 16, 32……\),但我們在用倍增求解\(lca\)的時候並不從小到大,而是從大到小來進行,\(……32, 16, 8, 4, 2, 1\),我們用這樣乙個圖來更好的理解

(**於網路)

在這顆樹中,\(17\)和\(18\)的\(lca\)就是\(3\)。

暴力的演算法就是讓兩者分別向上乙個乙個竄,直到兩者相遇。但是這個時間複雜度太大了,我們就需要用到倍增的演算法了。

我們從大往小了跳,如果大了,那麼我們就調小, 這回它的時間複雜度為\(o(nlogn)\)足夠我們在比賽中使用了,那麼該如何實現呢。

首先我們需要記錄每個節點他們的深度\(depth[x]\)和他們的\(2^i\)級祖先\(fa[i][j]\)(表示節點\(i\)的\(2^j\)級祖先)。

void dfs(int now, int fath)
此時我們已經進行玩了預處理,這裡我們先將\(lg\)陣列求解一遍,進行常數優化。

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

lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);

在這之後就是倍增\(lca\)了,我們先將兩個點提到同一高度,再統一的跳。注意這裡很重要,我第一遍學習的時候沒有理解透徹就是卡在了這裡。

但是我們不能直接跳到他們的\(lca\),因為我們是從大到小進行跳的,可能最開始直接跳到了根節點,根節點肯定是兩個點的祖先,但是不是我們要求的最短公共祖先,所以我們要往下再跳一層,發現誒兩者不一樣了,這樣的話,這一層就是兩者的最短公共祖先。

int lca(int x, int y)
所以在這個圖中,我們按照倍增\(lca\)的方法來求,路徑為:

\(17 -> 10 -> 7 -> 3\)

\(18 -> 16 -> 8 -> 5 -> 3\)

所以這就是整個過程了。

#include#include#define n 500010

using namespace std;

int n, m, s, cnt = 0;

int lg[n], head[n << 1];

int depth[n], fa[n][22];

struct edgee[n << 1];

void add(int u, int v)

void dfs(int now, int fath)

int lca(int x, int y)

int main()

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

lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);

dfs(s, 0);

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

return 0;

}

以上就是用倍增來實現\(lca\)的方法了,只有勤加練習,才能夠對其有更深刻的理解和掌握。

完結撒花ヾ(✿゚▽゚)ノ

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