倍增法求lca(最近公共祖先)

2022-08-19 05:51:11 字數 1869 閱讀 2377

基本上每篇部落格都會有參考文章,一是彌補不足,二是這本身也是我學習過程中找到的覺得好的資料

大致上演算法的思路是這樣發展來的。

想到求兩個結點的最小公共祖先,我們可以先把兩個的深度提到同一水平,在一步一步往上跳,直到兩個結點有了乙個公共祖先,依照演算法流程,這就是least common ancestor。

但是如果這樣一步步地往上未免太讓人著急,為了提高一下效率,便不再每次只跳一步,而跳\(2^i\)步。一般的,先這樣蹦蹦跳跳跳上去直到兩個結點相平,在兩個一起這樣蹦上去。

怎麼確定這個i該是多少合適呢?

這裡我們需要預處理乙個陣列f,f[u] [i]來表示結點u的第i代祖先,f[u] [0]表示結點u的父親,這個陣列用鏈式前向星(最近怎麼老是它)加上dfs來預處理產生,十分便捷。那它有什麼用呢?用在提公升結點的時候,我們可以借助這個陣列直接將結點提到他的合適的祖先上去。怎麼才算合適的祖先?現假設求lca(s,t)

分兩步,第一步是將低結點提到高結點(相對於葉節點)的深度上。這時候乙個for迴圈從s的第20代祖先開始(為什麼是二十代?可能一般的樹達不到這個深度),看能不能把s提上去後滿足\(depth[s]>=depth[t]\),不能滿足就看第十九代祖先這樣一直減少i,若滿足了就把s提上去,還是繼續減少i,直到兩個結點最終相平。這個過程有個部落格裡講的很形象(見參考文章),比喻成烏鴉喝水的過程,就是烏鴉先把體積大的(這裡就是i值)放進水杯裡,再逐漸減小放入物品的體積直到把水杯的水公升上來,而不是先填沙子這種小顆粒的東西。這就是為什麼i值要從大到小。

第二步是整體提公升的過程,我們不知道該幾步提公升,在迴圈中的條件就變成了\(if(f[s][i]!=f[t][i])\)。也就是只要他兩的祖先不一樣就提公升,祖先一樣有兩種可能,一種可能是節點是祖先但不是最小公共祖先,另一種可能是到了公共祖先。前一種出現在迴圈的開始,一開始想要提的深度比較多,所以很可能提到了公共祖先。這種情況不用管,繼續減小i值,之後可能會由於滿足\(if\)條件而經歷一些兩點提公升的過程,最後不滿足\(if\)條件了,說明兩個已經有了最小公共祖先,這時候隨意輸出乙個節點的父結點就行了。

演算法完成,看看**。如覺得不太清楚請看參考文章。

#include #include #define max_n 500005

using namespace std;

int n,m,s;//n為結點數,m為邊數,s為根節點標號

int lg[max_n];//優化用到的預處理的陣列,存log_2[i]-1

int f[max_n][23];//f[u][i]表示結點u的第i代祖先,其中f[u][0]為u的父結點

int depth[max_n];//節點深度

//鏈式前向星

int head[max_n];

struct edge

e[max_n<<1];

int cnt = 0;

void add(int u,int v)

//快速讀入模板

inline void read(int& x)

while('0'<=ch&&ch<='9')

x = f?-x:x;

}//dfs預處理出結點往上跳2^i的結點

void dfs(int u,int from)

if(s==t)//若t為s的祖先

for(int i = lg[depth[s]]-1;i>=0;i--)//待s,t相平後

}/*for(int i = 20;i>=0;i--)

}*/return f[s][0];//直到最後兩者公共祖先相等,記為lca

}int main()

for(int i = 1;idfs(s,0);

int ans = 0;

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

return 0;

}

樹上倍增求LCA(最近公共祖先)

前幾天做faebdc學長出的模擬題,第三題最後要倍增來優化,在學長的講解下,嘗試的學習和編了一下倍增求lca 我能說我其他方法也大會嗎?倍增求lca father i j 表示節點i往上跳2 j次後的節點 可以轉移為 father i j father father i j 1 j 1 此處注意迴圈...

模板 LCA 最近公共祖先 倍增法

2019 11 07 09 25 45 c.樹之呼吸 叄之型 樹上兩點路徑長度 time limit 1000 ms memory limit 32768 k total submit 7 4 users total accepted 2 2 users special judge no descr...

LCA最近公共祖先 倍增法筆記

先暫時把模板寫出來,a幾道題再來補充 此模板也是洛谷上的一道模板題 pragma gcc optimize 2 o2優化 include using namespace std typedef long long ll const int l 30 2的指數的大小 const int nn 1e6 ...