倍增求lca(模板)

2022-02-23 12:27:28 字數 1865 閱讀 8346

定義

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,int

fa)

for(int i=head[u];i;i=e[i].next)

}

有的預處理工作都完成了。我們開始求lca~

int lca(int x,int

y) }

//讓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...