定義
lca,最近公共祖先,是指一棵樹上兩個節點的深度最大的公共祖先。也可以理解為兩個節點之間的路徑上深度最小的點。
我們這裡用了倍增的方法求了lca。
我們的基本的思路就是,用dfs遍歷求出所有點的深度。f[i][j]陣列用來求的是距離節點i,距離2^j的祖先。可以知道,f[i][0]就是它的直接父親。然後通過倍增的思路求出father陣列的所有元素。然後進行lca。求lca的基本思路是:先讓深度較大的點向上跳,
然後x和y再同時向上跳2的冪,總會跳到這樣兩個點,他們的父親結點是同乙個點,那就是x和y的lca。
首先我們需要用鄰接表建一顆參天大樹~
重頭戲——倍增。
int dep[maxn],f[maxn][64];/*
dep陣列用來記錄當前點的深度
f[i][j]代表距離i 2^j的祖先
*/
深度和直接父親:
void pre(int u,intfa)
for(int i=head[u];i;i=e[i].next)
}
有的預處理工作都完成了。我們開始求lca~
int lca(int x,inty) }
//讓x跳到跟y相同高度上
if(x!=y)
}x=f[x][0
];
//這個時候x和y還不是同乙個節點,但是x和y的父親就是x和y的lca。
}
return
x;}
常數優化:另外預處理出lg避免重複呼叫log函式
for(int i=1;i<=n;i++)lg[i]=lg[i-1]+(1
<1]==i);
p3379 【模板】最近公共祖先(lca)
給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。
第一行包含三個正整數n、m、s,分別表示樹的結點個數、詢問的個數和樹根結點的序號。
接下來n-1行每行包含兩個正整數x、y,表示x結點和y結點之間有一條直接連線的邊(資料保證可以構成樹)。
接下來m行每行包含兩個正整數a、b,表示詢問a結點和b結點的最近公共祖先。
對於100%的資料:n<=500000,m<=500000
#include#include#include
#include
#include
#define num ch-'0'
#define rep(i,k,n) for(int i=k;i<=n;++i)
using
namespace
std;
int n,m,s,cnt=0
;int head[1000005],dep[1000005],fa[1000005][64],lg[1000005
];inline
void
get(int &res)
struct
node
e[1000005
];inline
void add(int x,int
y)void init(int u,intf)}
int lca(int x,int
y) x=fa[x][0
]; }
returnx;}
intmain()
init(s,0);
rep(i,
1,n) lg[i]=lg[i-1]+(1
<1]==i);
rep(i,
1,m)
return0;
}
參考
倍增LCA模板
注意!本篇題解不適合初學lca的同學學習,因為我講的很爛很不清楚。倍增,顧名思義,就是成倍增加的意思。我們知道,任何乙個數字都可以表示成二進位制。那麼對於一條長度為n的鏈,我們總是可以跳大概logn次到達最後。對於鏈上任意一點,我們都可以在大概logn的複雜度下詢問到,其實倍增的思路就是二分,和快速...
倍增法求 LCA
預處理 通過dfs遍歷,記錄每個節點到根節點的距離dist u 深度d u 並求出樹上每個節點i的2 j祖先f i j 求最近公共祖先,根據兩個節點的的深度,如不同,向上調整深度大的節點,使得兩個節點在同一層上,如果正好是祖先結束,否則,將連個節點同時上移,查詢最近公共祖先。include incl...
倍增法求lca
f i j 表示從i這個節點出發,向上走2 j步到達的點 超過了最大深度就返回0 那麼顯然有 因為相當於是從i點先向上走2 j 1 步,再走2 j 1 步。等價於一共走2 j步。然後求lca就是 先把深度大的那個點往上跳,使兩個點的深度相同。對應的 for int i 18 i 0 i if dep...