對於一棵樹來說,樹上兩個結點有lca。lca是指兩個結點所有公共祖先中,深度最大的。lca有很多性質,比如樹上兩點間最短路徑會經過lca(無負邊權),樹的dfs序中lca是兩點間深度最小的等等。
lca據說是noip幾乎每年必考內容,如何高效率地求lca很關鍵。不難想到一種暴力做法,從兩個點開始往上蹦,第一次重合處就是lca。時間複雜度是o(n)的,難以滿足要求。常用的正確做法是倍增。我們可以預處理出每個結點的2^0倍祖先(即父親),2^1倍祖先(父親的父親),2^2倍祖先(父親的父親的父親的父親),...然後在蹦的時候就可以一次蹦很高了。相當於是將兩個結點間深度差看成二進位制數,去列舉二進位制位。
具體來講,我們先預處理出每個結點的深度及各種父親。深度的話,子結點深度=父結點深度+1;設fa[i][j]表示結點i的2^j倍父親,則fa[i][j]=fa[fa[i][j-1]][j-1],結點i的2^j倍父親=結點i的2^(j-1)倍父親的2^(j-1)倍父親,沒毛病。然後我們讓深度較大的結點往上蹦,蹦到與另一結點在同一層上,若此時兩結點重合,則說明深度較小結點是另一結點的祖先;否則我們讓兩個結點一起蹦,蹦到重合。
1 #include2 #include3 #include4using
namespace
std;
5int n,fa[maxn][20],int
d[maxn],head[maxn],eid;
6struct edge e[maxn];
9void insert(int u,int
v) 14
void dfs(int
u) 22}23
int lca(int x,int
y)
最近公共祖先 LCA 最近公共祖先
直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...
最近公共祖先 最近公共祖先(LCA)
如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...
LCA 最近公共祖先
定義 對於有根樹t的兩個結點u v,最近公共祖先lca t,u,v 表示乙個結點x,滿足x是u v的祖先且x的深度盡可能大。另一種理解方式是把t理解為乙個無向無環圖,而lca t,u,v 即u到v的最短路上深度最小的點。現在給定乙個根為1的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...