题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

在线版本:

在线方法的思路很简单,就是倍增。一遍dfs得到每个节点的父亲,以及每个点的深度。然后用dp得出每个节点向上跳2^k步到达的节点。

那么对于一个查询u,v,不妨设depth[u]>=depth[v],先让u向上跳depth[u]-depth[v]步,跳的方法就是直接用数字的二进制表示跳。

然后现在u和v都在同一深度上了,再二分找向上共同的祖先,就可以二分出lca了。复杂度nlogn预处理+qlogn查询。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3.  
  4. int read()
  5. {
  6. char c=getchar();
  7. while (!isdigit(c)) c=getchar();
  8. int x=;
  9. while (isdigit(c))
  10. {
  11. x=x*+c-'';
  12. c=getchar();
  13. }
  14. return x;
  15. }
  16.  
  17. const int maxn=;
  18. const int maxm=maxn*;
  19. int head[maxn];
  20. struct Edge
  21. {
  22. int u,v,w,nxt;
  23. }edge[maxm];
  24. int tot;
  25.  
  26. void init()
  27. {
  28. tot=;
  29. memset(head,-,sizeof(head));
  30. }
  31.  
  32. void addedge(int u,int v,int w)
  33. {
  34. ++tot;
  35. edge[tot].u=u;
  36. edge[tot].v=v;
  37. edge[tot].w=w;
  38. edge[tot].nxt=head[u];
  39. head[u]=tot;
  40. }
  41.  
  42. int dep[maxn];
  43. int pa[maxn];
  44. int dis[maxn];
  45.  
  46. void dfs(int u,int f,int de,int d)
  47. {
  48. pa[u]=f;
  49. dep[u]=de;
  50. dis[u]=d;
  51. for (int i=head[u];i!=-;i=edge[i].nxt)
  52. {
  53. int v=edge[i].v;
  54. int w=edge[i].w;
  55. if (v!=f)
  56. {
  57. dfs(v,u,de+,d+w);
  58. }
  59. }
  60. }
  61.  
  62. int fa[maxn][];
  63.  
  64. int getlca(int u,int v)
  65. {
  66. if (dep[u]<dep[v]) swap(u,v);
  67. int jump=dep[u]-dep[v];
  68. for (int i=;i<;i++)
  69. {
  70. if (jump&) u=fa[u][i];
  71. jump>>=;
  72. }
  73. for (int i=;i>=;i--)
  74. {
  75. if (fa[u][i]!=fa[v][i])
  76. {
  77. u=fa[u][i];
  78. v=fa[v][i];
  79. }
  80. }
  81. if (u!=v) return pa[u];
  82. else return u;
  83. }
  84.  
  85. int main()
  86. {
  87. int t;
  88. t=read();
  89. while (t--)
  90. {
  91. init();
  92. int n,q;
  93. n=read();
  94. q=read();
  95. for (int i=;i<n-;i++)
  96. {
  97. int u,v,w;
  98. u=read();
  99. v=read();
  100. w=read();
  101. addedge(u,v,w);
  102. addedge(v,u,w);
  103. }
  104. dfs(,,,);
  105. for (int i=;i<=n;i++) fa[i][]=pa[i];
  106. for (int i=;i<;i++)
  107. for (int j=;j<=n;j++)
  108. fa[j][i]=fa[fa[j][i-]][i-];
  109. while (q--)
  110. {
  111. int u,v;
  112. u=read();
  113. v=read();
  114. int lca=getlca(u,v);
  115. int ans=dis[u]+dis[v]-*dis[lca];
  116. printf("%d\n",ans);
  117. }
  118. }
  119. return ;
  120. }

离线版本:

离线版本复杂度低,所以有时候还是很有必要会的。(有一次比赛在线的做法就被卡常了)

离线版本的思路是:每个点都把与它有关的查询放进它的那个vector里,然后对这棵树进行一次dfs,在dfs的过程中直接得出所有查询的答案,复杂度是O(n+q)。

具体来说,假设有一个查询u,v,当遍历到u的时候,如果v还没有遍历,就先不管这个查询;如果v已经遍历过了,那就处理这个查询,那么这个查询的结果是什么呢?结果就是v向上一直找,找到深度最浅的那个已经遍历过并且当前正在考虑这棵子树的节点,就是u和v的lca。这是用到了dfs的中序遍历性质,很难表达清楚,可以通过想象感觉一下。那么怎么得到v向上一直找,找到最浅的那个已经遍历过的节点呢?并查集。具体可以参照代码,这个感觉真的只能通过想象感觉出来,确实很难表述。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3.  
  4. int read()
  5. {
  6. char c=getchar();
  7. while (!isdigit(c)) c=getchar();
  8. int x=;
  9. while (isdigit(c))
  10. {
  11. x=x*+c-'';
  12. c=getchar();
  13. }
  14. return x;
  15. }
  16.  
  17. const int maxn=;
  18. const int maxm=maxn*;
  19. int head[maxn];
  20. struct Edge
  21. {
  22. int u,v,w,nxt;
  23. }edge[maxm];
  24. int tot;
  25.  
  26. void init()
  27. {
  28. tot=;
  29. memset(head,-,sizeof(head));
  30. }
  31.  
  32. void addedge(int u,int v,int w)
  33. {
  34. ++tot;
  35. edge[tot].u=u;
  36. edge[tot].v=v;
  37. edge[tot].w=w;
  38. edge[tot].nxt=head[u];
  39. head[u]=tot;
  40. }
  41.  
  42. vector< pair<int,int> > Q[maxn];
  43. bool vis[maxn];
  44. int fa[maxn];
  45. int ans[];
  46. int dis[maxn];
  47.  
  48. void addquery(int u,int v,int id)
  49. {
  50. Q[u].push_back(make_pair(v,id));
  51. Q[v].push_back(make_pair(u,id));
  52. }
  53.  
  54. int findfa(int x)
  55. {
  56. if (fa[x]==x) return x;
  57. return fa[x]=findfa(fa[x]);
  58. }
  59.  
  60. int n,q;
  61.  
  62. void dfs(int u,int d)
  63. {
  64. dis[u]=d;
  65. vis[u]=true;
  66. for (int i=head[u];i!=-;i=edge[i].nxt)
  67. {
  68. int v=edge[i].v;
  69. int w=edge[i].w;
  70. if (!vis[v])
  71. {
  72. dfs(v,d+w);
  73. fa[v]=u;
  74. }
  75. }
  76. for (int i=;i<Q[u].size();i++)
  77. {
  78. int v=Q[u][i].first;
  79. int id=Q[u][i].second;
  80. if (vis[v]) ans[id]=dis[u]+dis[v]-*dis[findfa(v)];
  81. }
  82. }
  83.  
  84. int main()
  85. {
  86. int t;
  87. t=read();
  88. while (t--)
  89. {
  90. init();
  91. n=read();
  92. q=read();
  93. for (int i=;i<n-;i++)
  94. {
  95. int u,v,w;
  96. u=read();
  97. v=read();
  98. w=read();
  99. addedge(u,v,w);
  100. addedge(v,u,w);
  101. }
  102. for (int i=;i<maxn;i++) Q[i].clear();
  103. memset(vis,false,sizeof(vis));
  104. for (int i=;i<=n;i++) fa[i]=i;
  105. for (int i=;i<q;i++)
  106. {
  107. int u,v;
  108. u=read();
  109. v=read();
  110. addquery(u,v,i);
  111. }
  112. dfs(,);
  113. for (int i=;i<q;i++) printf("%d\n",ans[i]);
  114. }
  115. return ;
  116. }

[hdu 2586]lca模板题(在线+离线两种版本)的更多相关文章

  1. HDU 2586 (LCA模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2586 题目大意:在一个无向树上,求一条链权和. 解题思路: 0 | 1 /   \ 2      3 ...

  2. hdu - 2586 (LCA板子题)

    传送门 (这次的英文题面要比上一个容易看多了) (英语蒟蒻的卑微) 又是一个很裸的LCA题 (显然,这次不太容易打暴力咧) (但听说还是有大佬用dfs直接a掉了) 正好 趁这个机会复习一下LCA 这里 ...

  3. hdu 2586 How far away?(LCA模板题+离线tarjan算法)

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. POJ 1470 Closest Common Ancestors (模板题)(Tarjan离线)【LCA】

    <题目链接> 题目大意:给你一棵树,然后进行q次询问,然后要你统计这q次询问中指定的两个节点最近公共祖先出现的次数. 解题分析:LCA模板题,下面用的是离线Tarjan来解决.并且为了代码 ...

  5. 【转载】pygame安装与两种版本的Python兼容问题

    在开始学习游戏编程之前,我们先来安装下pygame和python3.2.5 参考园友: http://www.cnblogs.com/hongten/p/hongten_pygame_install. ...

  6. HDU - 2586 How far away ?(LCA模板题)

    HDU - 2586 How far away ? Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & ...

  7. HDU 2586——How far away ?——————【LCA模板题】

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  8. HDU2586 How far away ?(LCA模板题)

    题目链接:传送门 题意: 给定一棵树,求两个点之间的距离. 分析: LCA 的模板题目 ans = dis[u]+dis[v] - 2*dis[lca(u,v)]; 在线算法:详细解说 传送门 代码例 ...

  9. HDU 2586 LCA

    题目大意: 多点形成一棵树,树上边有权值,给出一堆询问,求出每个询问中两个点的距离 这里求两个点的距离可以直接理解为求出两个点到根节点的权值之和,再减去2倍的最近公共祖先到根节点的距离 这是自己第一道 ...

随机推荐

  1. flask(列表实现)

    在 index/views.py 中定义视图函数 在查询的时候,如果用户分类id传0,则不添加分类查询条件 @index_blu.route('/newslist') def get_news_lis ...

  2. Python自动化运维——系统性能信息模块

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 模块:psutil psutil是一个跨平台库,可以很轻松的为我们实现获取系统运行的进程和资源利用率等信息. 功能 ...

  3. Spring + MySQL + Mybatis + Redis【二级缓存】执行流程分析

    一级缓存基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就 ...

  4. 也谈js传值和传址

    通常的认识就是基本的数值元素是传值,对象等复杂结构传址,无需争论,一试便知. 首先是数值 var a = 1 var b = a a = 2 console.log(a) console.log(b) ...

  5. GreenMail邮件测试服务器

    GreenMail邮件测试服务器 http://blog.csdn.net/jackiehff/article/details/8741988 这个目前没有需求,所以暂不研究

  6. 谷歌js编码规范解析

    http://alloyteam.github.io/JX/doc/specification/google-javascript.xm 阅读了谷歌js编码规范,我发现了很多,js的里面很多要注意的问 ...

  7. PHP将两个数组相加

    $arr_a=[1=>1,2=>2,3=>3];$arr_b=[1=>'a',4=>4];print_r($arr_a+$arr_b);返回结果:Array ( [1] ...

  8. 【转】ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了

    原文链接:https://www.cnblogs.com/yilezhu/p/9241261.html 引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必 ...

  9. 关于缺失值(missing value)的处理---机器学习 Imputer

    关于缺失值(missing value)的处理 在sklearn的preprocessing包中包含了对数据集中缺失值的处理,主要是应用Imputer类进行处理. 首先需要说明的是,numpy的数组中 ...

  10. kvm-1

    yum install libvirt* virt-* qemu-kvm* -y systemctl start libvirtd.service systemctl status libvirtd. ...