首先了解一下我們 最近公共祖先
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 深 每次檢查中,若是,...