還是老樣子,觀察一下lca的分類:
emmmm,真好。關於樹上距離很明顯就不用再多說了,那麼就直接開始lca的演算法詳解↓
對於lca,算是oi中比較重要的一種演算法了,下面先了解一下關於lca的分析↓
lca(最近公共祖先):在有根樹當中,節點u和v的公共祖先中最小的那乙個點。
比如:
其中,lca(7,8)=5,lca(4,7)=2,lca(4,6)=1;
或者也可以理解為無向無環圖,lca(u,v)即為u->v的最短路上深度最小的點。就有
4->7: 4->2->5->7,其中2的深度為2,最小,∴lca(4,7)=2;
當然不建議這種做法,祂的時間複雜度可能會很高(博主也沒有試過)。
以下是博主常用的幾種做法。
簡單地說,就是標記其中乙個點的所有祖先,然後由另乙個點回溯,直到訪問到被標記的點。例如上圖的lca(4,7),從4開始,標記4 2 1,7回溯到5,在回溯到2,被標記過,則答案為2。
code:
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
int n,m,s,
ver[
1000001
],hed[
1000001
],nxt[
1000001
],tot=
0,deep[
500001
],fa[
500001
],bj[
500001
],b[
500001];
void
add(
int x,
int y)
void
dfs(
int x)}}
intmain()
b[s]=1
;dfs
(s);
for(
int i=
1,x,y;i<=m;i++
)for
(int i=fa[y]
;i;i=fa[i])if
(bj[i])}
return0;
}
這本質上是暴力解法的優化演算法,記錄每乙個點的深度,並且調製至同深度,然後二進位制向上走,直到兩個點的標記位置達到第一次相同時,該節點即為答案。
code:
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
queue<
int> q;
int n,m,s,
ver[
1000001
],hed[
1000001
],nxt[
1000001
],tot=
0,deep[
500001
],f[
500001][
20];void
add(
int x,
int y)
void
bfs(
int a)}}
intlca
(int x,
int y)
intmain()
t=(int)
(log
(n)/
log(2)
)+1;
bfs(s)
;for
(int i=
1,x,y;i<=m;i++
)return0;
}
說句實在話,就是使用並查集對暴力解法進行優化,是乙個離線演算法。
過程很簡單,就是每次從乙個節點u開始,把u向下的節點視為以u為根的樹,再搜尋其他節點。每搜尋完乙個點後,如果該點和另乙個已搜尋完點為需要查詢lca的點,則這兩點的lca為另乙個點的現在的祖先。
1.先建立兩個鍊錶,乙個為樹的各條邊,另乙個是需要查詢最近公共祖先的兩節點。
2.建好後,從根節點開始進行一遍深搜。
3.先把該節點u的father設為他自己(也就是只看大樹的一部分,把那一部分看作是一棵樹),搜尋與此節點相連的所有點v,如果點v沒被搜尋過,則進入點v的深搜,深搜完後把點v的father設為點u。
4.深搜完一點u後,開始判斷節點u與另一節點v是否滿足求lca的條件,滿足則將結果存入陣列中。
5.搜尋完所有點,自動退出初始的第乙個深搜,輸出結果。
時間複雜度為o(m+n)
code:
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
template
<
typename type>
inline
void
read
(type &xx)
struct edgee[
1000001];
struct questions
}q[1000001];
bool b[
500001];
int head[
500001
],que[
500001
],father[
500001
],n,m,s,nume=
0,numq=
0,ans[
500001];
void
add_edge
(int x,
int y)
void
add_que
(int x,
int y,
int k)
intfind
(int x)
void
unionn
(int x,
int y)
void
lca(
int point,
int f)
for(
int i=que[point]
;i!=
0;i=q[i]
.next)if(
!q[i]
.flag&&b[q[i]
.to])}
intmain()
father[n]
=n;for
(int i=
1,x,y;i<=m;i++
)lca
(s,0);
for(
int i=
1;i<=m;i++
)printf
("%d\n"
,ans[i]);
return0;
}
ps:等待**…… Mysql資料亂碼完美解答
下面我大致的來解釋一下圖一的變數名稱的含義 character set client 來自客戶端的語句的字符集,採用這個字元 集對客戶端語句進行解析 character set connection 用於沒有字符集匯入符的文字和數字 字串轉換 character set database 預設資料庫...
Mysql資料亂碼完美解答
下面我大致的來解釋一下圖一的變數名稱的含義 圖1 character set client 來自客戶端的語句的字符集,採用這個字元 集對客戶端語句進行解析 character set connection 用於沒有字符集匯入符的文字和數字 字串轉換 character set database 預設...
倍增LCA複習
時間過去了如此之久,我連倍增lca都不怎麼記得了,要粗事啊。首先預處理層數和每個節點的父親,然後預處理p陣列,p i,j 表示i向上第2 j個祖先。最後對於每個詢問x,y先把x,y變成同一層數的 x或y向上走直到兩個層數相等 然後x,y同時向上走,直到x和y的父親相同位置。自 1.dfs預處理出所有...