LCA 最近公共祖先的四種解法

2022-08-20 23:39:17 字數 2926 閱讀 1258

給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。

樹的構造-舉個栗子

尤拉序

儲存第一次出現的位置

使用鏈式前向星儲存樹的結構,首先求一棵樹的尤拉序,然後根據兩點的公共祖先就是尤拉序中(第一次出現時)兩點位置區間內的深度最小點,

這一定理轉化成rmq最小問題,使用st表時注意log2的複雜度比較高,st表總體速度較慢,約900ms

#include#define for(i,a,b) for(int i=a;i'9'||ch

ch=getchar();

if(ch=='-')

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

return x*f;

}inline void put(int x)

int num=0;

char c[25];

while(x)

while(num)

putchar(c[num--]);

putchar('\n');

return ;

}inline int log2(int x)

inline void dfs(int pre,int cur,int level)

if(pre!=cur) }

inline void add(int a,int b)

int main()

dfs(0,s,1);

//rmq

int logh=log2(cnt);

for(int h=1;h<=logh;h++)

}\)次能到達的祖先節點,

然後讀取要求的點\(a,b\),處理成同一深度後,若\(b\)是\(a\)的祖先,則返回b,

若不是,則同時上跳\(2^}\)次,直到相等.

時間比st表快,約550ms。預處理時間複雜度o(nlogn),每次查詢時間複雜度o(logn)

#include#define for(i,a,b) for(int i=a;i'9'||ch

ch=getchar();

if(ch=='-')

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

return x*f;

}inline void put(int x)

int num=0;

char c[25];

while(x)

while(num)

putchar(c[num--]);

putchar('\n');

return ;

}inline int log2(int x)

inline void add(int a,int b)

void dfs(int cur,int pre)

} return jump[x][0];//返回父節點

}int main()

dfs(s,0);

for(i,0,m)

return 0;

}

先選擇乙個節點u為根節點,從根節點開始搜尋。(標記u已訪問過)

遍歷該點u的所有兒子節點v,並標記v已訪問過。

若v還有兒子節點,對v重複ii操作,否則進入下一操作。

把v合併到u上(並查集)。

把當前的點設為u,遍歷與u有詢問關係的節點v。

如果v在之前已經被訪問過,那麼u和v的最近公共祖先就是v通過並查集合並後的父親節點(注意是合併後),即當前的find(v)。

預處理時間複雜度o(nlogn),每次查詢時間複雜度o(1),總時間複雜度是o(nlogn+q),約400ms

tarjan偽**

tarjan(u)//marge和find為並查集合並函式和查詢函式

for each(u,e) //訪問所有和u有詢問關係的e

}

#include#define for(i,a,b) for(int i=a;i'9'||ch

ch=getchar();

if(ch=='-')

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

return x*f;

}inline void put(int x)

int num=0;

char c[25];

while(x)

while(num)

putchar(c[num--]);

putchar('\n');

return ;

}inline int log2(int x)

inline void add(int a,int b)

inline void vadd(int a,int b)

inline int find(int x)

void tarjan(int u)

for(int i=vhead[u];i;i=vedges[i].next) }

}int main()

for(i,0,m)

tarjan(s);

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

put(lca[i*2]);

return 0;

}

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

LCA 最近公共祖先

定義 對於有根樹t的兩個結點u v,最近公共祖先lca t,u,v 表示乙個結點x,滿足x是u v的祖先且x的深度盡可能大。另一種理解方式是把t理解為乙個無向無環圖,而lca t,u,v 即u到v的最短路上深度最小的點。現在給定乙個根為1的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...