1. 程式人生 > >【模板】LCA(尤拉序+RMQ)

【模板】LCA(尤拉序+RMQ)

完整部分點這裡

平常在資訊學競賽中求LCA一般有三種辦法:

  • 倍增法求解,預處理複雜度是 O(nlogn) ,每次詢問的複雜度是 O(logn), 屬於線上解法。
  • 利用尤拉序轉化為RMQ問題,用 ST表 求解RMQ問題,預處理複雜度 O(n+nlogn) ,每次詢問的複雜度為 O(1), 也是線上演算法。
  • 採用Tarjan演算法求解,複雜度 O(α(n)+Q) ,屬於離線演算法。

上述三種演算法都比較常用,這篇文章主要介紹第二種解法。

先介紹一下尤拉序:
對有根樹T進行深度優先遍歷,無論是遞迴還是回溯,每次到達一個節點就把編號記錄下來,得到一個長度為

2N1 的序列,成為樹 T 的尤拉序列F。

如圖1(Inkscape手畫,略醜輕噴~):

圖1

1T

按照深度優先遍歷我們可以得到它的尤拉序和深度序列:

1FB
序號 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
尤拉序列F 1 2 5 2 6 2 1 3 1 4 7 8 7 4 1
深度序列B 1 2 3 2 3 2 1 2 1 2 3 4 3 2 1

為了方便,我們定義 first(u) 表示 u 結點的第一次出現的位置,那麼我們根據上面的表格就可以得到 n 個結點各自的 first 值:

2first
序號 1 2 3 4 5 6 7 8
first() 1 2 8 10 3 5 11 12

根據深度優先遍歷的特點,我們可以知道,對於結點 u 和結點 v, 我們不妨假設 u

v 之前被遍歷,也就是說 first(u)<first(v) ,那麼在 u 遍歷到 v 過程中深度最小的點就是 LCA(u,v) (這一點在Tarjan演算法中也有運用)。

這樣一來,我們就可以將 LCA 問題轉化為RMQ問題:LCA(T,u,v)=RMQ(B,first(u),first(v))

舉個栗子:

仍然以上圖為例,假定 u=6 , v=8 在圖上很明顯能夠看出 LCA(u,v)=1 。同時我們把代表從 u 遍歷到 v 的這個序列”抽“出來:

3FB
序號 5 6 7 8 9 10 11 12
尤拉序列F’ 6 2 1 3 1 4 7 8
深度序列B’ 3 2 1 2 1 2 3 4

為什麼要從原序列中抽取 5 ~ 12 這個串呢?原因很簡單,first(6)=5first(8)=12 ,這個值上面的表已經給出了。

可以看出,在這個序列中,深度最小的點的序號是