p3379 最近公共祖先lca
給定一有根樹,給定兩個點,求這兩個節點的最近公共祖先。
定義乙個陣列fa[
i][e
]fa[i][e]
fa[i][
e],表示第i
ii個節點,沿著i→r
i \to r
i→r的路徑走2e2^
2e步的祖先節點,模擬與stst
st表,2 e+
12^+1
2e+1
就是路徑長度。特別的,e=0
e=0e=
0的時候表示節點的父節點。
然後通過dfs
dfsdf
s遍歷的方式計算出整棵樹的fafa
fa陣列,通過一下公式:
f a[
i][e
]=fa
[fa[
i][e
−1]]
[e−1
]fa[i][e] = fa[fa[i][e-1]][e-1]
fa[i][
e]=f
a[fa
[i][
e−1]
][e−
1]
void
dfs(
int curr,
int root)
for(
int i = head[curr]
; i !=
0; i = e[i]
.nxt)
}}
然後進行lca
(x,y
)lca(x,y)
lca(x,
y),首先判斷x
xx和y
yy是否在同乙個深度上,如果不是,那麼將深度大的那個節點移動到深度小的那個節點上。此時如果x=y
x=yx=
y說明x
xx和y
yy就是lca
lcalc
a,否則進行移動,從大的e
ee開始嘗試,一直嘗試到兩個節點不相等為止,此時的父節點就是lca
lcalc
a。
#
include
using
namespace std;
struct
edge
;edge e[
500001
<<1]
;int tot =0;
int head[
500001];
int log[
500005];
int depth[
500005];
int fa[
500005][
20];void
add(
int x,
int y)
void
dfs(
int curr,
int root)
for(
int i = head[curr]
; i !=
0; i = e[i]
.nxt)}}
intlca
(int u,
int v)
while
(depth[u]
!= depth[v])if
(u == v)
return u;
for(
int i = log[depth[u]
]; i>=
0; i--)}
return fa[u][0
];}int
main()
for(
int i =
2; i<
500005
; i++
) log[i]
= log[i >>1]
+1;dfs
(s,s)
;while
(n--
)return0;
}
詳見樹鏈剖分。
o (n
logn)
o(n \log n)
o(nlogn)
時間預處理,o(1
)o(1)
o(1)
時間查詢。
我們定義dsf訪問序列:
每一次進入節點和退出節點均需要記錄:
序號節點id深度1
***x2xx
xx則我們查詢lca是在表中兩個節點id之間的最小深度所對應的節點id。
如果有多個節點id,任意選取即可。
使用st表進行靜態rmq查詢。
#
include
#define
frfreopen
("in.txt"
,"r"
,stdin
)typedef
long
long ll;
using
namespace std;
int n, m, s;
struct
edge
e[1000005];
int head[
500005];
int tot =0;
struct
tour
t[1000005];
int tot2 =0;
int idx[
500005];
int st[
1000005][
25];int log[
1000005];
void
add(
int u,
int v)
void
add2
(int u,
int dep)
void
dfs(
int u,
int r,
int dep)
}int
min(
int a,
int b)
void
initst()
for(
int i = tot2; i >=
1; i--)}
}int
query
(int l,
int r)
intlca
(int a,
int b)
intmain()
scanf
("%d %d %d"
,&n,
&m,&s)
;for
(int i =
0; i < n -
1; i++
)dfs
(s, s,0)
;for
(int i =
1; i <= tot2; i++
)initst()
;for
(int i =
0; i < m; i++
)return0;
}
最近公共祖先 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的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...