最近公共祖先 LCA 問題

2022-05-01 19:06:10 字數 1376 閱讀 3625

目錄定義:給定一顆有根樹,若結點 z 既是 x 的祖先,也是 y 的祖先,則稱 z 是 x,y 的公共祖先。在 x,y 所有的公共祖先中,深度最大的乙個稱為 x,y 的最近公共祖先,簡稱\(lca(x,y)\)。

求解最近公共祖先一般有三種解法:向上標記法,樹上倍增法和 tarjan 演算法。

即對於任何兩個結點 x , y ,分別從x y 向上走並標記它們所有經過的節點,第一次相遇的節點即為最近公共祖先。其時間複雜度最壞為\(o(n^2)\)。

樹上倍增法在很多問題都有很廣泛的應用,當然最近公共祖先也可以用樹上倍增演算法來求,其基本思想是:

設d[x]>=d[y],其中d[x]表示x的深度,然後利用二進位制思想,將x不斷調整直至和y在同一深度,檢查此時x和y是否相等,若相等即為最近公共祖先,否則將x,y一起向上調整直至相等,此時則為最近公共祖先。

該演算法時間複雜度為:\(o((n+m)logn)\)具體**(裸題,求權值)為:

#includeusing namespace std;

const int maxn=5e5+10;

int head[maxn],dis[maxn],d[maxn],f[maxn][20];

struct edge

edge[maxn<<1];

int t,t,n,m,tot;

queueq;

void init()

void add(int from,int to,int val)

void bfs()

}}int lca(int x,int y)

}return f[x][0];

}int main()

edge[maxn<<1];

int t,n,m,t,tot;

int head[maxn],fa[maxn],v[maxn],dis[maxn],ans[maxe];

vectorquery[maxn],query_id[maxn];

void init()

}void add(int from,int to,int val)

void add_query(int x,int y,int id)

int ffind(int x)

void tarjan(int x)

for(int i=0;i}

v[x]=2;

}int main()

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

}tarjan(1);

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

printf("%d\n",ans[i]);

}system("pause");

}

最近公共祖先 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)

最近公共祖先問題 lca 下面的內容來自演算法藝術與資訊學競賽一書 lca問題 給出乙個有根樹t,對於任意兩個節點u和v,求出 lca t,u,v 即離根最遠的結點x,使得x同時是u和v的祖先。從上面的遞推方法,給我們乙個啟示。當l u l v 時,可以根據lca u,v 的答案把所有結點分成若干個...