一.倍增演算法的前期鋪墊
我們記節點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中深度較大的乙個,然後讓其向上跳,直到兩個節點的深度相同,當深度相同時,兩個節點開始同時往上跳,直到兩個節...