Luogu P3379 LCA問題的倍增解法

2022-06-06 08:21:09 字數 1213 閱讀 3256

luogu p3379

題意:對於兩個節點,尋找他們的最近公共祖先。

乙個顯而易見的解法是對於每乙個節點我們都往上遍歷一遍,記錄下它每乙個祖先,然後再從另乙個節點出發,一步一步往上走,找到以前記錄過第乙個節點就是這兩個節點的lca

事實上在這樣的資料規模下,這種解法的時間複雜度是讓人無法接受的。

很容易發現,這樣的解法慢在兩個節點是一步一步往上走的,也許可以想個辦法一次跳一大步?

於是我們引入了倍增法求lca。

我們知道,對於任意乙個整數數,都可以使用\(2^k+2^+...+2^0\)來表示,這是不需要證明的,因為二進位制能表示十進位制的每乙個數。

那麼我們就可以每一次跳\(2^k\)步來優化這個演算法。

還有乙個問題就是:我們應該從大的開始跳還是從小的開始跳呢?

答案是從大的開始,因為如果從小的開始,就有可能出現需要回溯的情況。

舉個例子,如果從小的開始,我們就會湊出\(5=1+2+...\),發現不對,然後回溯,湊出\(5=1+4\),但是如果從大的開始就可以直接湊\(5=4+1\),只要判斷一下加了這個數比要求的數要大就可以不要這個,取更小的。

但是我們會發現在做這件事之前,我們必須要知道兩個節點的深度以便跳步,並且還需要預處理每乙個節點的\(2^k\) 級的祖先。

乙個dfs就可以輕鬆完成這個任務。

void add(int sta,int to)

//如果沒有看懂可以尋找其他博主的資料

void dfs(int fa,int now)

最後是完整**:

#include#include#includeusing namespace std;

struct data

edge[500005<<1];

int cnt,head[500005],deepth[500005],ant[500005][21],lg[500005],n,m,s,x,y;

void add(int sta,int to)

void dfs(int fa,int now)

int main()

dfs(0,s);

for (int i=1;i<=n;i++) lg[i]=lg[i-1]+(1

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

return 0;

}

P3379最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...

P3379 模板 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問a結點和b...

P3379 模板 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問a結點和b...