【简介】

解决LCA问题的倍增法是一种基于倍增思想的在线算法。

【原理】

原理和同样是使用倍增思想的RMQ-ST 算法类似,比较简单,想清楚后很容易实现。

对于每个节点u , ancestors[u][k] 表示 u 的第2k个祖先是谁。很容易就想到递推式: ancestors[j][i] = ancestors[ancestors[j][i - 1]][i - 1];  根据二进制原理,理论上 u 的所有祖先都可以根据ancestors数组多次跳转得到,这样就间接地记录了每个节点的祖先信息。
     查询LCA(u,v)的时候:
         (一)u和v所在的树的层数如果一样,令u'=u。否则需要平衡操作(假设u更深),先找到u的一个祖先u', 使得u'的层数和v一样,此时LCA(u,v)=LCA(u',v) 。证明很简单:如果LCA(u,v)=v , 那么u'一定等于v ;如果LCA(u,v)=k ,k!=v ,那么k 的深度一定小于 v , u、u'、v 一定在k的子树中;综上所述,LCA(u,v)=LCA(u',v)一定成立。

(二)此时u' 和 v 的祖先序列中一开始的部分一定有所重叠,重叠部分的最后一个元素(也就是深度最深,与u'、v最近的元素)就是所求的LCA(u,v)。这里ancestors数组就可以派上用场了。找到第一个不重叠的节点k,LCA(u,v)=ancestors[k][0] 。 找k的过程利用二进制贪心思想,先尽可能跳到最上层的祖先,如果两祖先相等,说明完全可以跳小点,跳的距离除2,这样一步步跳下去一定可以找到k。

【hdu 2586】

需要注意的是超界的处理。

  1. #pragma comment(linker, "/STACK:1024000000,1024000000")
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <vector>
  5. #include <cmath>
  6. #include <iostream>
  7. using namespace std;
  8. int n,m;
  9. struct edge
  10. {
  11. int d,v,next;
  12. edge(){}
  13. edge(int _d,int _v,int _next)
  14. {
  15. d=_d;v=_v;next=_next;
  16. }
  17. }data[];
  18. int map[];
  19. int pool;
  20. void addedge(int s,int e,int v)
  21. {
  22. int t=map[s];
  23. data[pool++]=edge(e,v,t);
  24. map[s]=pool-;
  25. }
  26. int ANCLOG;
  27. int depth[];
  28. int ifv[];
  29. int dis[];
  30. int anc[][];
  31. void dfs(int cur,int dep)
  32. {
  33. ifv[cur]=;
  34. depth[cur]=dep;
  35. int p=map[cur];
  36. while (p!=-)
  37. {
  38. if (!ifv[data[p].d])
  39. {
  40. dis[data[p].d]=dis[cur]+data[p].v;
  41. anc[data[p].d][]=cur;
  42. dfs(data[p].d,dep+);
  43. }
  44. p=data[p].next;
  45. }
  46. }
  47. void initLCA()
  48. {
  49. for (int k=;k<ANCLOG;++k)
  50. for (int i=;i<n;++i)
  51. {
  52. if (anc[i][k-]==-) continue;
  53. anc[i][k]=anc[anc[i][k-]][k-];
  54. }
  55. }
  56. int getLCA(int u,int v)
  57. {
  58. if (depth[u]<depth[v]) swap(u,v);
  59. for (int k=ANCLOG;k>=;--k)
  60. {
  61. if (anc[u][k]==-) continue;
  62. if (depth[anc[u][k]]>=depth[v])
  63. {
  64. u=anc[u][k];
  65. if (depth[u]==depth[v]) break;
  66. }
  67. }
  68. if (u==v) return u;
  69. for (int k=ANCLOG;k>=;--k)
  70. {
  71. if (anc[u][k]==-) continue;
  72. if (anc[u][k]!=anc[v][k])
  73. {
  74. u=anc[u][k];
  75. v=anc[v][k];
  76. }
  77. }
  78. return anc[u][];
  79. }
  80. int main()
  81. {
  82. int T;
  83. scanf("%d",&T);
  84. while (T--)
  85. {
  86. pool=;
  87. memset(anc,-,sizeof anc);
  88. memset(map,-,sizeof map);
  89. memset(ifv,,sizeof ifv);
  90. scanf("%d%d",&n,&m);
  91. ANCLOG=(int)(log(n)/log(2.0));
  92. int s,e,v;
  93. for (int i=;i<n-;++i)
  94. {
  95. scanf("%d%d%d",&s,&e,&v);
  96. addedge(s-,e-,v);
  97. addedge(e-,s-,v);
  98. }
  99. dis[]=;
  100. dfs(,);
  101. initLCA();
  102. for (int i=;i<m;++i)
  103. {
  104. int u,v;
  105. scanf("%d%d",&u,&v);
  106. --u;--v;
  107. int k=getLCA(u,v);
  108. k=dis[u]+dis[v]-*dis[k];
  109. printf("%d\n",k);
  110. }
  111. }
  112. }

最近公共祖先 LCA 倍增法的更多相关文章

  1. luogu3379 【模板】最近公共祖先(LCA) 倍增法

    题目大意:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 整体步骤:1.使两个点深度相同:2.使两个点相同. 这两个步骤都可用倍增法进行优化.定义每个节点的Elder[i]为该节点的2^k( ...

  2. 【lhyaaa】最近公共祖先LCA——倍增!!!

    高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...

  3. 最近公共祖先 LCA 倍增算法

          树上倍增求LCA LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 ...

  4. LCA(最近公共祖先)——LCA倍增法

    一.前人种树 博客:最近公共祖先 LCA 倍增法 博客:浅谈倍增法求LCA 二.沙场练兵 题目:POJ 1330 Nearest Common Ancestors 代码: const int MAXN ...

  5. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

  6. 最近公共祖先(LCA)的三种求解方法

    转载来自:https://blog.andrewei.info/2015/10/08/e6-9c-80-e8-bf-91-e5-85-ac-e5-85-b1-e7-a5-96-e5-85-88lca- ...

  7. POJ - 1330 Nearest Common Ancestors(dfs+ST在线算法|LCA倍增法)

    1.输入树中的节点数N,输入树中的N-1条边.最后输入2个点,输出它们的最近公共祖先. 2.裸的最近公共祖先. 3. dfs+ST在线算法: /* LCA(POJ 1330) 在线算法 DFS+ST ...

  8. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  9. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

随机推荐

  1. Perl6 Bailador框架(3):路径匹配

    use v6; use Bailador; =begin pod 注意的是, 当/:one设置时 虽然你有/admin或/about, 但这个/:one不会跟现有的匹配 只跟没有的匹配: 也就是说, ...

  2. Xmind 8 update5 破解

    Step 1. Download XMind Step 2. Run XMind at least once after installation, xmind will init the confi ...

  3. python基础===时间处理模块

    时间模块 Python中有很多方便我们处理时间信息的模块 time 模块 datetime 模块 pytz 模块 dateutil 模块 这里我们着重介绍的是前两种 time模块 time.time( ...

  4. FreeRADIUS + MySQL 安装配置笔记

    FreeRADIUS + MySQL 安装配置笔记 https://www.2cto.com/net/201110/106597.html

  5. xshell+xming连接服务器虚拟机启动mininet网络

    困于vnc连实验室的服务器虚拟机,一直出现页面不稳定的情况,然后本机虚拟机又带不起来,今天跟学弟交流,知道了ssh连接服务器的办法,心情好晴朗! xshell下载和安装,xshell使用 xshell ...

  6. python的IDLE界面回退代码语句

    Alt+P回退到IDLE中之前输入的代码语句 Alt+N可以移至下一个代码语句

  7. Hadoop(hadoop,HBase)组件import到eclipse

    1.简介: 将源代码import到eclipse可以方便的阅读和修改源码. 2.环境说明: mac mvn工具(Apache Maven 3.3.3 ) 3.hadoop(CDH5.4.2) 1.进入 ...

  8. ZOJ-2753

    Min Cut (Destroy Trade Net) Time Limit: 15 Seconds      Memory Limit: 32768 KB Given an undirected g ...

  9. highcharts 折线,饼状,条状综合图

    完整代码如下: <head> <meta http-equiv="Content-Type" content="text/html; charset=u ...

  10. 常用模块二(hashlib、configparser、logging)

    阅读目录 常用模块二 hashlib模块 configparse模块 logging模块   常用模块二 返回顶部 hashlib模块 Python的hashlib提供了常见的摘要算法,如MD5,SH ...