給定一棵有 n
nn 個點的樹,回答 q
qq 組點對 (a,
b)
(a,b)
(a,b
) 的最近公共祖先。
資料範圍1⩽n
,m
⩽10000000
1\leqslant n,m\leqslant 10000000
1⩽n,m⩽
1000
0000
%
維護乙個並查集,一開始所有點的祖先都是自己,先進行一次深度優先遍歷,每次離開乙個點的時候,將其標記為已到達,並遍歷詢問中(鄰接表儲存)和這個點有關的詢問,若另乙個點標記為已到達,則答案為另乙個點在並查集中的祖先(後面),最後讓這個點在並查集中認自己的真實父親作父親。
如此,每個點會且僅會被遍歷一次,在離開的時候,和某個點相關的詢問會且只會被訪問兩次,考慮到此處並查集必須嚴格按照原樹的結構合併,不能按秩合併,因而最壞時間複雜度為 t(n
)=θ(
nlog1
+mnn
+2q)
t(n)=\theta(n\log_ n+2q)
t(n)=θ
(nlog1+n
mn
+2q)
這是時間複雜度低於倍增的離線演算法,名稱也是tarjan
\texttt
tarjan
演算法。
#include
using
namespace std;
#define maxn 500010
struct edgeedges[maxn<<1]
,que[maxn<<1]
;int head[maxn]
,hque[maxn]
,len=
0,ques=0;
void
ins_edge
(int u,
int v)
; head[u]
=len;
}void
ins_que
(int u,
int v,
int code)
; hque[u]
=ques;
}int n,q,f[maxn]
,d[maxn]
;int
findfa
(int x)
struct dfsssta[maxn]
;int top=0;
bool vis[maxn]
;int ans[maxn]
;void
dfs(
int tt)
;while
(top>0)
;break
;} head[u]
=edges[head[u]
].next;
if(sta[top]
.u==u)}}
intmain()
for(
int i=
1,a,b;i<=q;i++
)dfs
(tt)
;for
(int i=
1;i<=q;i++
)printf
("%d\n"
,ans[i]);
return0;
}
最近公共祖先 python 最近公共祖先
lca演算法樸素演算法 也就是我們所說的暴力演算法,大致的思路是從樹根開始,往下迭代,如果當前結點比兩個結點都小,那麼說明要從樹的右子樹中找 相反則從左子樹中查詢 直到找到乙個結點在當前結點的左邊,乙個在右邊,說明當前結點為最近公共祖先,如果乙個結點是另外乙個結點的祖先,那麼返回前面結點的父親結點即...
最近公共祖先 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,表示詢問...