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 ", lca(a, b)); 72 } 73 return 0; 74 }
怎么样
很好理解吧www