LCA 最近公共祖先 (倍增演算法)

2021-10-04 01:48:19 字數 3934 閱讀 6431

首先了解一下我們 最近公共祖先

e和g的lca為a

l和j的lca為d

k和f的lca為b

然後 倍增 用到了二進位制和 dp 的思想

倍增 就是 1 2 4 8 16 …任何乙個數 都是可以右 這些數相加得到的。(了解一下二進位制)

首先 定義:

fa[ i ] [ j ] 為 從 i 節點 向上走 2 ^ j 個節點,

depth[ i ] 為節點 i 的深度。

舉個例子 fa[ k ][ 1 ]=b , fa[ i ][ 0 ]=d ;

depth[ h ]=3,depth[ a ]=1;

定義完這個 我們就可以通過 乙個 dfs 把 每個節點的深度 和 每個節點向上走 1 步 都求出來

**

void

dfs(

int u,

int pre,

int d)

}

ps :當時聽學長講的時候有點懵 不是求公共祖先嗎 這個有什麼用呢 到後面發現挺神奇的

接下來 我們就要想辦法把 每個節點向上走 n 步 給表示出來

前面說過 1 2 4 8 16 … 這些二進位制數是可以把所有的數都表示出來的 所以我們只要 把每乙個節點向上走 2 ^ n 表示出來 就可以把走任意步都表示出來了。

考慮一下 我們可以發現

fa[ i ] [ j ]=fa[ fa[ i ] [ j-1 ] ][ j-1 ] 。

就是 說 如果我們要求 i 向上走 8 不步 可以由 i 先走 4 步 再 走 4 步 得到。 我們可以用 dp 實現這個步驟

**

void

init

(int root)

}}

做完這些預處理 接下來就是找最近公共祖先的步驟了

ps 四處盜圖 哈哈

首先 我們讓 所求的兩個節點處於 同一深度 然後一起向上跳就行了

至於怎麼跳 就比較關鍵了

最簡單的方法 就是乙個點乙個點的跳直到 到達相同的節點(這樣肯定會超時的。。。。。。。)

所以換一種思路 就是 這種方法的核心了

像 上圖的 15 16 這兩個節點 處於同一深度

我們要想辦法 讓他們 跳到 最近公共祖先的下面乙個節點

採取 這樣的 策略 從 2 ^ k到 2^0 步進行列舉

如果 他們跳了 2^k 步之後 到達了 同乙個節點 說明 我們到達了 最近公共祖先 或者 以上的節點 不符合我們的要求 (不跳)。

過程中如果 碰到跳完後到達了不同的節點 例如 2^0 我們就讓他跳 (可以去找個大一點的樹模擬一下)

最後 我們會神奇的發現 他們 來到了 6 和 10 這兩個節點

所以 最近公共祖先就為 fa[ 6 ][0 ];

是不是很神奇 (我學的時候感覺挺神奇的)

**:

int

lca(

int u,

int v)

if(u==v)

return u;

for(

int i=

log(n*

1.0)

/log

(2.0

);i>=

0;i--)}

return fa[u][0];}

來個 題目

凜冬將至 (csust 2023年集訓隊選拔賽)

description

維斯特洛大陸的原住民是森林之子,他們長得如孩童一般,善於使用石器,威力值35,用樹葉樹枝作為衣物,在森林裡繁衍生息,與萬物和平相處。他們會使用古老的魔法(比如綠之視野),威力值55。後來先民從維斯特洛大陸架登陸,憑藉手中的青銅兵器和戰馬大舉入侵,威力值分別是35和55。森林之子憑藉魔法頑強抵抗,並冒險利用龍晶製造出了乙個神奇的強悍的物種——異鬼,威力值60。雙方持久不下之時簽訂了和平協議,先民佔據了維斯特洛大陸,森林之子只保有森林。

七大王國如火如荼興起之時,在遙遠海洋的另一端,乙個神秘的家族悄然興起——坦格利安家族。此家族擁有三條巨龍,威力值90+,經過乙個世紀的備戰,在領導者伊耿一世的帶領下乘龍入侵維斯特洛大陸。

借助龍的力量,伊耿一世很快統一了維斯特洛的七大王國,建立了空前強大的坦格利安王朝,像所有外來入侵者一樣,坦格利安家族摒棄了龍的信仰開始信仰七神,並且將龍由放養改為圈養,再加上坦格利安家族為了保持血統純正,實行近親婚姻,生出來的繼承者精神病人越來越多,這導讓坦格利安王朝開始了眼花繚亂的花樣作死之旅。

眾(wo)所(xia)周(che)知(de),當凱特琳·徒利得知自己女兒艾莉亞逃到赫倫堡後,非常擔心女兒的安全。假設維斯特洛大陸共有nn個城市,共有n-1n−1條雙向道路把這nn個城市連線起來。也就是說這是一棵樹。凱特琳想盡快臨冬城趕到赫倫堡。除了已知的n-1n−1條邊外,凱特琳還知道一條額外的秘密路徑(也是雙向的):端點是是城市xx和城市yy,路徑長度是zz。現在想考考寒假過後的你有沒有刷過題,問你qq個問題,每個問題給出臨冬城(凱特琳所在城市)和赫倫堡(艾莉亞所在城市)的座標,請你告訴凱特琳從臨冬城到赫倫堡的最短路徑長度是多少?

input

第一行乙個整數n(1<=n<=100000)

以下n-1行描述一顆樹,每行u,v,w表示一條從u到v長為w的路徑,u!=v。

下一行三個整數x,y,z 意義如題(1<= x,y<=n, x!=y)。

下一行乙個整數q(100000)

以下q行兩個數字u,v代表臨冬城和赫倫堡的座標。

1≤w,z≤1000

output

對每次詢問輸出從臨冬城到赫倫堡的最短路徑長度。

**

#include

#include

#include

#include

#include

#include

#include

using

namespace std;

typedef

long

long ll;

const

int maxn=

1e6;

const

int mod=

1e9+7;

int head[maxn]

,num=

0,depth[maxn]

,fa[maxn][32

],n,vis[maxn]

,dis[maxn]

;struct nodee[maxn]

;void

add(

int u,

int v,

int w)

void

dfs(

int u,

int pre,

int d)

}void

init

(int root)}}

intlca

(int u,

int v)

if(u==v)

return u;

for(

int i=

log(n*

1.0)

/log

(2.0

);i>=

0;i--)}

return fa[u][0

];}intd(

int u,

int v)

int main (

)scanf

("%d%d%d"

,&x,

&y,&z)

;for

(int i=

1;i<=n;i++)}

init

(root)

;int k;

cin>>k;

while

(k--

)}

最近公共祖先 LCA 倍增演算法

樹上倍增求lca lca指的是最近公共祖先 least common ancestors 如下圖所示 4和5的lca就是2 那怎麼求呢?最粗暴的方法就是先dfs一次,處理出每個點的深度 然後把深度更深的那乙個點 4 乙個點地乙個點地往上跳,直到到某個點 3 和另外那個點 5 的深度一樣 然後兩個點一...

LCA 最近公共祖先)之倍增演算法

概述 對於有根樹t的兩個結點u v,最近公共祖先lca t,u,v 表示乙個結點x,滿足x是u v的祖先且x的深度盡可能大。如圖,3和5的最近公共祖先是1,5和2的最近公共祖先是4 在本篇中我們先介紹一下倍增演算法 我們需要乙個陣列de i 來表示每乙個節點i的深度,用另一陣列parent i j ...

樹,LCA,最近公共祖先,倍增

最近公共祖先,樹上倍增,lca,fa i j 表示 i 節點向上 2j 的祖先 很像dp,k 屬於 1 log n f x k f f x k 1 k 1 算lca時,先不妨設 d x d y 二進位制拆分 嘗試從x 向上走 k 2log n 21,20,檢查到的點是否比 y 深 每次檢查中,若是,...