It is the path you have chosen. Take pride in it. Kotomine Kirei

GldHkkowo

关于LCA的倍增解法的笔记

  emmmmm近日刚刚学习了LCA的倍增做法,写一篇BLOG来加强一下印象w

 

  首先 何为LCA? 

 

 

  LCA“光辉”是印度斯坦航空公司(HAL)为满足印度空军需要研制的单座单发轻型全天候超音速战斗攻击机,主要任务是...

  LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。

  怎么样,很好理解吧!

  然后,关于倍增

  emmmmm,可以这么理解:

  ……

  ……

  ……

  https://blog.csdn.net/jarjingx/article/details/8180560(太烂啦有空再自己填一下这个坑吧x

  怎么样,很好理解吧!

  (懒癌患者是这样的orz,对不住各位观众老爷&&神犇啦

  那么!

  怎么把他们结合在一起就是我们要研究的问题啦。

  相信大家第一次看到形似“给出一棵树和若干结点,求他们的LCA”这种问题就会想到爆搜吧(单次最坏和平均时间复杂度都是O(n))

  但是显而易见,万恶机智的出题人是不会放我们这么简单的做法过哒

  这时候我们就需要在原来的爆搜上加上倍增优化一下时间复杂度(优化之后是O(nlogn))

  我们给这种神秘地操作叫做 树上倍增

  总而言之就是

  用一个二维数组fa[i][j]来表示从第i个结点向上跳 2 ^ j 个结点所在的点,那么理所当然的fa[i][0]表示的就是i点的父结点啦

  

 1 int lca(int x, int y) {
 2     if (dep[x] > dep[y]) {
 3         swap(x, y);  //交换x点和y点,让x点在y点上♂面(噫
 4     }
 5     for (int i = 20; i >= 0; i--) { 
 6         if (dep[y] - (1 << i) >= dep[x]) {
 7             y = fa[y][i];     //把y点调整到和x点一个高度
 8         }
 9     }
10     if(x == y) {
11         return x;   //这里是特判哦,如果调整后x点和y点一样直接返回x就行啦
12     }
13     for(int i = 20; i >= 0; i--) {
14         if(fa[x][i] == fa[y][i]) {
15             continue;  //如果他们的父亲向上跳2 ^ i个点后是同一个点的话就找到他们的LCA啦
16         }
17         else {
18             x = fa[x][i]; 
19             y = fa[y][i];  //要雨♂露♂均♂沾,一起向上跳喏
20         }
21     }
22     return fa[x][0]; 返回LCAqwqqq
23 }

 

  以上就是倍增LCA的核心算法啦

  然而要知道的是,现在有许多万恶机智的出题人是会卡我们的倍增哒

  所以我们就需要

  优化优化优化!

  因为涉及到图,我们就可以用一种叫派大星链式前向星的东西来优化它(如果你不知道链式前向星可以看看这个

   下面以洛谷的模板题为例,贴一下自己的代码(感谢kkogoro带我“走进LCA”wwww
  
 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 const int Maxv = 500001; 
 7 
 8 int fa[Maxv * 2][21], head[Maxv], dep[Maxv]; 
 9 int cnt, n, m, s;
10 
11 struct edges {
12     int v, next; 
13 }edge[Maxv * 2];
14 
15 void add(int x, int y){
16     edge[cnt].v = y; 
17     edge[cnt].next = head[x]; 
18     head[x] = cnt++;
19 }
20 
21 void dfs(int u, int father){
22     dep[u] = dep[father] + 1; 
23     fa[u][0] = father; 
24     for (int i = 1; (1 << i) <= dep[u]; i++) {
25         fa[u][i] = fa[fa[u][i - 1]][i - 1]; 
26     }
27     for (int i = head[u]; i != -1; i = edge[i].next) {
28         int v = edge[i].v;
29         if (v != father) {
30             dfs(v, u);
31         }
32     }
33 }
34 
35 int lca(int x, int y) {
36     if (dep[x] > dep[y]) {
37         swap(x, y);
38     }
39     for (int i = 20; i >= 0; i--) {
40         if (dep[y] - (1 << i) >= dep[x]) {
41             y = fa[y][i]; 
42         }
43     }
44     if(x == y) {
45         return x; 
46     }
47     for(int i = 20; i >= 0; i--) {
48         if(fa[x][i] == fa[y][i]) {
49             continue; 
50         }
51         else {
52             x = fa[x][i]; 
53             y = fa[y][i]; 
54         }
55     }
56     return fa[x][0]; 
57 }
58 
59 int main(){
60     int a, b; 
61     memset(head, -1, sizeof(head));
62     scanf("%d %d %d", &n, &m, &s); 
63     for (int i = 1; i < n; i++) {
64         scanf("%d %d", &a, &b);
65         add(a, b);
66         add(b, a);
67     }
68     dfs(s, 0); 
69     for(int i = 1; i <= m; i++) {
70         scanf("%d %d", &a, &b);
71         printf("%d\n", lca(a, b));
72     }
73     return 0; 
74 }

 

  怎么样
  很好理解吧www

posted on 2018-04-07 21:34  GldHkkowo  阅读(177)  评论(0编辑  收藏  举报

导航