最近公共祖先線性演算法

2021-09-26 01:56:09 字數 1716 閱讀 6153

給定一棵有 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

)=θ(

nlog⁡1

+mnn

+2q)

t(n)=\theta(n\log_ n+2q)

t(n)=θ

(nlog1+n

m​​n

+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,表示詢問...