最近公共祖先~讲解
最近公共祖先(Lowest Common Ancestors):
簡稱LCA(并不是某輕型戰斗機)
一.何為最近公共祖先
對于有根樹T的兩個結點u、v,最近公共祖先LCA(T,u,v)表示一個結點x,滿足x是u、v的祖先且x的深度盡可能大。(摘自百度百科)
那么舉個簡單的例子:看圖
那么比如14和18的lca就是3 ? 11和16的lca就是5
對于求lca,有很多種方法:tarjan啦,樹剖啦,倍增啦,暴力......
二.如何求最近公共祖先呢
首先我們想到了:暴力大法好
對于所求的兩個點,調整到同一個深度,然后一起向上跳,這樣所求到的第一個相同的點就是這兩個點的lca。
可是暴力肯定會T...那么怎么辦呢
我們想到了之前學過的st表,利用倍增的思想來完成lca的查詢。
接著我們想到了:倍增大法好
1.首先我們準備好要用到的變量
所有點的2^j層的父親,用fa數組保存,對于fa[i][j]表示編號為i的點向上跳2^j步的父親。maxlog用來枚舉j。
head,edge,cnt鄰接表的標配,不用多說。deep[i]表示i的深度,root為所給定的根節點編號。add為向樹中添加一條邊。
1 const int maxlog = 20; 2 const int maxn = 550000; 3 int n, m, s; 4 int root; 5 int fa[maxn][maxlog]; 6 int deep[maxn]; 7 int head[maxn]; 8 int cnt; 9 struct Edge{ 10 int next; 11 int to; 12 }e[2*maxn]; 13 void add(int u, int v) 14 { 15 e[cnt].to = v; 16 e[cnt].next = head[u]; 17 head[u] = cnt++; 18 }2.初始化建樹,預處理每個點的fa數組
dfs建樹,ini初始化fa數組。
1 void dfs(int u, int p, int d) 2 { 3 fa[u][0] = p; 4 deep[u] = d; 5 for(int i = head[u]; i != -1; i = e[i].next) 6 if(e[i].to != p) dfs(e[i].to, u, d+1); 7 } 8 void init() 9 { 10 dfs (root, -1, 0); 11 for(int k = 0; k + 1 < maxlog; k++) 12 { 13 for(int v = 1; v <= n; v++) 14 if(fa[v][k] < 0) fa[v][k+1] = -1; 15 else fa[v][k+1] = fa[fa[v][k]][k]; 16 } 17 }3.接下來就是關于倍增lca的精髓所在:
(劃重點!)我們對于每一個點,還是先移動到同一高度,再開始跳。
對于第一個for便是移動到相同深度。
對于兩個已經跳到了相同深度的兩個點,我們從最高處向下跳,直到遇見一個兩個點fa都不相同的點,即他們的lca下面的兩個點。再求出這個兩個點的向上跳一步的父節點。即lca。
1 int lca(int u, int v) 2 { 3 if(deep[u] > deep[v]) swap(u, v); 4 for(int k = 0; k < maxlog; k++) 5 { 6 if(deep[v] == deep[u]) break; 7 if((deep[v] - deep[u]) >> k & 1) 8 { 9 v = fa[v][k]; 10 //cout<<deep[v]<<" "<<deep[u]<<endl; 11 }//向上跳到同樣深度 12 } 13 14 if(u == v) return u; 15 16 for(int k = maxlog - 1; k >= 0; k--) 17 { 18 if(fa[v][k] != fa[u][k]) 19 { 20 u = fa[u][k]; 21 v = fa[v][k]; 22 //cout<<u<<" "<<v<<endl; 23 } 24 25 }//從大向小跳下去 , 第一個遇到的不同的 26 return fa[u][0]; 27 }模板:
https://www.luogu.org/problemnew/show/P3379
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 const int maxlog = 20; 7 const int maxn = 550000; 8 int n, m, s; 9 int root; 10 int fa[maxn][maxlog]; 11 int deep[maxn]; 12 int head[maxn]; 13 int cnt; 14 struct Edge{ 15 int next; 16 int to; 17 }e[2*maxn]; 18 void add(int u, int v) 19 { 20 e[cnt].to = v; 21 e[cnt].next = head[u]; 22 head[u] = cnt++; 23 } 24 void dfs(int u, int p, int d) 25 { 26 fa[u][0] = p; 27 deep[u] = d; 28 for(int i = head[u]; i != -1; i = e[i].next) 29 if(e[i].to != p) dfs(e[i].to, u, d+1); 30 } 31 void init() 32 { 33 dfs (root, -1, 0); 34 for(int k = 0; k + 1 < maxlog; k++) 35 { 36 for(int v = 1; v <= n; v++) 37 if(fa[v][k] < 0) fa[v][k+1] = -1; 38 else fa[v][k+1] = fa[fa[v][k]][k]; 39 } 40 } 41 int lca(int u, int v) 42 { 43 if(deep[u] > deep[v]) swap(u, v); 44 for(int k = 0; k < maxlog; k++) 45 { 46 if(deep[v] == deep[u]) break; 47 if((deep[v] - deep[u]) >> k & 1) 48 { 49 v = fa[v][k]; 50 //cout<<deep[v]<<" "<<deep[u]<<endl; 51 } 52 } 53 54 if(u == v) return u; 55 56 for(int k = maxlog - 1; k >= 0; k--) 57 { 58 if(fa[v][k] != fa[u][k]) 59 { 60 u = fa[u][k]; 61 v = fa[v][k]; 62 } 63 } 64 return fa[u][0]; 65 } 66 int main() 67 { 68 memset(head,-1,sizeof(head)); 69 int a,b; 70 scanf("%d%d%d",&n,&m,&root); 71 for(int i = 1; i < n; i++) 72 { 73 scanf("%d%d",&a,&b); 74 add(a,b); 75 add(b,a); 76 } 77 init(); 78 for(int i = 1; i <= m; i++) 79 { 80 int u,v,a; 81 scanf("%d%d",&u,&v); 82 a = lca(u,v); 83 printf("%d\n",a); 84 } 85 return 0; 86 }?
轉載于:https://www.cnblogs.com/MisakaAzusa/p/8612942.html
總結
- 上一篇: 软件测试例子
- 下一篇: Elasticsearch和HDFS 容