LCA倍增演算法

2022-05-15 08:46:18 字數 1315 閱讀 6788

一.倍增演算法的前期鋪墊

我們記節點v到根的深度為depth(v)。那麼如果節點w是節點u和節點v的最近公共祖先的話,讓u往上走(depth(u)-depth(w))步,讓v往上走(depth(v)-depth(w))步,都將走到節點w。因此,我們首先讓u和v中較深的乙個往上走|depth(u)-depth(v)|步,再一起一步步往上走,直到走到同乙個節點,就可以在o(depth(u)+depth(v))的時間內求出lca。

由於節點的最大深度為n,所以這個方法在最壞的情況下一次查詢時間複雜度就要o(n),這顯然是不夠的。於是我們開始考慮優化。

二.倍增演算法的實現過程

分析剛才的演算法,兩個節點到達同一節點後,不論怎麼向上走,達到的顯然還是同一節點。利用這一點,我們就能夠利用二分搜尋求出到達最近公共祖先的最小步數了。

首先我們要進行預處理。對於任意的節點,可以通過fa2[v]=fa[fa[v]]得到其向上走2步到達的頂點,再利用這個資訊,又可以通過fa4[v]=fa2[fa2[v]]得到其向上走4步所到的頂點。以此類推,我們可以得到其向上走2^k步所到的頂點fa[v][k],預處理的時間點複雜度為o(nlogn)。

有了k=floor(logn)以內的所有資訊後,就可以進行二分所搜的,每次查詢的時間複雜度為o(logn)。

以poj1330為例

#include#include

#include

#include

#include

using

namespace

std;

vector

v[10010

];int fa[10010][100];//

fa[i][j]表示從i節點走2^j步可以達到的祖先節點

int depth[10010];//

記錄每個節點的深度

intn;

void dfs(int u,int pre,int

dep)

}void init(int

root)

} }int lca(int u,int

v)

}if(v==u)

return

u;

for(int i=int(log(n*1.0));i>=0;i--)

}return fa[u][0];}

intmain()

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

}//coutscanf(

"%d%d

",&x,&y);

printf(

"%d\n

",lca(x,y));

}}

lca倍增演算法模板

時間限制 1 sec 記憶體限制 128 mb 提交 244 解決 36 提交 狀態 給一棵樹,節點數為n 1 n 250,000 和q 0 q 100,000 個詢問,對於每個詢問求出所求兩點的最近公共祖先 第一行 節點數n 以下n行,第i 1行 點i的父親節點father i 假定根的父親是0 ...

LCA的倍增演算法

lca,即樹上兩點之間的公共祖先,求這樣乙個公共祖先有很多種方法 每次將深度大的點往上移動,直至二者相遇 在o 2n 預處理重鏈之後,每次就將深度大的沿重鏈向上,直至二者在一條鏈上 先記錄所有的詢問,對樹進行一次dfs,對於搜尋到的點u,先將點u往下搜,再將點u與父節點所在集合合併,之後對於它的所有...

LCA的倍增演算法

對於兩個節點的lca,根據兩個節點的關係分為一下兩種 一 其中一方是另一方的祖先 那u和v的公共祖先就是是祖先的那一方 二 雙方都不是對方的祖先 u和v的祖先x的深度比u和v小,我們先找出u和v中深度較大的乙個,然後讓其向上跳,直到兩個節點的深度相同,當深度相同時,兩個節點開始同時往上跳,直到兩個節...