最近公共祖先

2022-05-05 12:18:08 字數 2027 閱讀 1862

錢菜雞水平不行,只能寫寫最近公共祖先了。

目前 oi 所流行的 \(o(nlogn) - o(1)\) 的 lca 演算法是 尤拉序 + rmq,顯然,尤拉序沒有這麼好寫,而且常數不小(序列長度兩倍),所以導致了很多情況下更多人選擇了倍增等演算法。

尤拉序+rmq 演算法中,我們要實現乙個 \(2n\) 長度的序列的 rmq,但是我們發現,我們詢問的端點數量卻最多只有 \(n\) 個,這意味這我們可以將某些連續的段給縮起來。

縮起來後就成了乙個序列 \(a\),我們記 \(idfn_i\) 為滿足 \(dfn_ = i\) 的乙個數,容易發現 \(a_i = lca(idfn_, idfn_)\),顯然,我們求 \(x, y (dfn_x <= dfn_y)\) 的 lca 只需要求出 \(a_i (dfn_x \leq i \lt dfn_y)\) 中 \(dfn\) 最小的節點 (注意,需要特判 \(x = y\))。

下面我們的問題是如何求 \(a_i\)。可以證明的是 \(a_i = lca(idfn_, idfn_) = fa_}\),因此可以在一次 \(dfs\) 內簡單的求出 \(a\) 陣列。於是我們只用做一次長度為 \(n\) 的 rmq 預處理,在 \(o(n) - o(1)\) lca 中也有不錯的優化效果。

\(o(nlogn) - o(1)\)

#includeconst int maxn = 500500;

int n, m, s;

struct t way[maxn << 1];

int h[maxn], num;

int st[20][maxn], dfn[maxn], tot;

inline int min(int x,int y)

inline void link(int x,int y) , h[x] = num;

way[++num] = , h[y] = num;

}inline void dfs(int x,int fa = 0)

inline int lca(int x,int y)

int main()

}

\(o(n) - o(1)\):

#includeconst int maxn = 1000001;

typedef unsigned u32;

struct istream

inline istream& operator >> (int & x)

} cin;

struct ostream

vout = buf + size;

} inline ~ ostream()

inline ostream& operator << (int x)

inline ostream& operator << (char x)

} cout;

int n,q;

int a[maxn],dfn[maxn],tot;

namespace rmq

inline void down(int & x,int y)

inline int qry(int l,int r)

inline int rmq(int l,int r)

inline void build(int n)

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

for(int j = 0;j + (1 << i) - 1 <= n / 32;++j)

st[i][j] = min(st[i - 1][j],st[i - 1][j + (1 << i - 1)]); }}

struct t way[maxn << 1];

int h[maxn],num;

inline void adde(int x,int y), h[x]=num;

way[++num] = , h[y]=num;

}inline void dfs(int x,int f)

inline int lca(int x,int y)

int ans[maxn];

int main()

最近公共祖先 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,表示詢問...