树上倍增方法求LCA(最近公共祖先)(转)
来源:互联网 发布:淘宝卖家怎么看收入呢 编辑:程序博客网 时间:2024/04/29 15:59
初学LCA,菜菜的我还是先去逛逛各位大佬的博客,结果发现了神奇的东西。
LCA指的是最近公共祖先(Least Common Ancestors),如下图所示:
4和5的LCA就是2
那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度
然后把深度更深的那一个点(4)一个点地一个点地往上跳,直到到某个点(3)和另外那个点(5)的深度一样
然后两个点一起一个点地一个点地往上跳,直到到某个点(就是最近公共祖先)两个点“变”成了一个点
不过有没有发现一个点地一个点地跳很浪费时间?
如果一下子跳到目标点内存又可能不支持,相对来说倍增的性价比算是很高的
倍增的话就是一次跳2i 个点,不难发现深度差为x时,深度更深的那个点就需要跳x个点
于是可以写出这段代码
1 if(depth[a] < depth[b]) swap(a, b);2 int c = depth[a] - depth[b];3 for(int i = 0; i <= 14; i++){4 if(c & (1 << i)){5 a = up[a][i];6 }7 }
接下来很快就会发现一个很严重的问题:两个点按照这样跳,不能保证一定是最近的
所以倍增找lca的方法是这样的:
从最大可以跳的步数开始跳(一定是2i),如果跳的到的位置一样,就不跳,如果不一样才跳,每次跳的路程是前一次的一半
过程大概就像上图所示,但是执行完了这一段到的点不是最近公共祖先,但是,它们再往上跳一格,就到了
把这一段写成代码,就成了这样:
1 for(int i = 14; i >= 0; i--){2 if(up[a][i] != up[b][i]){3 a = up[a][i];4 b = up[b][i];5 }6 }
前面还需要加上一句特判(当a和b在同一边时,深度浅的那个点就是最近公共祖先)
if(a == b) return a;
好了,会求lca了,关键是怎么构造倍增数组。
没有疑问的是向上跳一格就是自己的父节点
f[i][0] = fa[i];
这个是初值,接着可以根据这个推出来其他的,除此之外还要附上初值0,不然有可能会RE
f[i][j] = f[f[i][j - 1]][j - 1];
就是把这一段路,分成两段已经知道的
完整代码就是这样的:
1 Matrix<int> up; 2 inline void init_bz(){ 3 up = Matrix<int>(16, n + 1); 4 memset(up.p, 0, sizeof(int) * 16 * (n + 1)); 5 for(int i = 1; i <= n; i++){ 6 up[i][0] = fa[i]; 7 } 8 for(int j = 1; j <= 14; j++){ 9 for(int i = 1; i <= n; i++){10 up[i][j] = up[up[i][j - 1]][j - 1];11 }12 }13 }
0 0
- 树上倍增方法求LCA(最近公共祖先)(转)
- 树上倍增求LCA(最近公共祖先)
- 最近公共祖先(LCA)之树上倍增法
- 倍增法求最近公共祖先(LCA)
- 最近公共祖先(LCA)---倍增法
- 最近公共祖先(LCA):倍增
- 倍增法求最近公共祖先 lca
- 树上两点最近公共祖先LCA的倍增算法 poj1986
- 【原创】【LCA】求最近公共祖先的三种方法(一)倍增 ※【USACO MAR11银组】聚会地点
- 求lca(最近公共祖先)的各种方法
- 求LCA(最近公共祖先)
- 【讲解+模板】最近公共祖先(LCA)(倍增)
- LCA最近公共祖先(朴素+倍增法)
- 最近公共祖先(LCA):tarjan与倍增
- lca(最近公共祖先)倍增模板【pascal】
- LCA(最近公共祖先)倍增法模板及总结
- lca最近公共祖先(st表/倍增)
- LCA(最近公共祖先)倍增法实现
- 设计模式系列之一:单例模式
- C++之虚函数(三)虚继承和虚基类详解
- leetcode 100.Same Tree
- 485. Max Consecutive Ones
- 刘凯stm32教程第21讲总结
- 树上倍增方法求LCA(最近公共祖先)(转)
- 博客
- 文章标题
- 手机号码验证
- SPFA 跑得快,跑得快。最小花费问题
- TensorFlow系列01——TensorFlow1.0正式发布
- 【JZOJ3617】【ZJOI2014】力
- Mysql备份延迟测试
- Game—围圈比赛