目錄定義:給定一顆有根樹,若結點 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 的答案把所有結點分成若干個...