【算法】最近公共祖先(LCA)

【题解】

点x,y到最近公共祖先z的距离之和相当于x,y到根的距离减去两倍z到根的距离,

即ans=dis[x]+dis[y]-2*dis[z]

记得边数组要开两倍!!!T_T

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. const double eps=1e-;
  5. const int maxn=;
  6. struct cyc{int from,to,w;}e[maxn*];
  7. int dis[maxn],deep[maxn],f[maxn][],n,q,cnt,head[maxn];
  8. bool vis[maxn];
  9. void insert(int u,int v,int w)
  10. {cnt++;e[cnt].from=head[u];e[cnt].to=v;e[cnt].w=w;head[u]=cnt;}
  11. void dfs(int x)
  12. {
  13. vis[x]=;
  14. for(int i=;(<<i)<=deep[x];i++)
  15. f[x][i]=f[f[x][i-]][i-];
  16. for(int i=head[x];i;i=e[i].from)
  17. if(!vis[e[i].to])
  18. {
  19. int now=e[i].to;
  20. deep[now]=deep[x]+;
  21. dis[now]=dis[x]+e[i].w;
  22. f[now][]=x;
  23. dfs(now);
  24. }
  25. }
  26. int lca(int x,int y)
  27. {
  28. if(deep[x]<deep[y])swap(x,y);
  29. int d=deep[x]-deep[y];
  30. for(int i=;(<<i)<=d;i++)
  31. if((<<i)&d)x=f[x][i];
  32. if(x==y)return x;
  33. for(int i=;i>=;i--)
  34. if(f[x][i]!=f[y][i])
  35. x=f[x][i],y=f[y][i];
  36. return f[x][];
  37. }
  38. int main()
  39. {
  40. scanf("%d%d",&n,&q);
  41. for(int i=;i<n;i++)
  42. {
  43. int u,v,w;
  44. scanf("%d%d%d",&u,&v,&w);
  45. insert(u,v,w);
  46. insert(v,u,w);
  47. }
  48. dfs();
  49. for(int i=;i<=q;i++)
  50. {
  51. int p1,p2;
  52. scanf("%d%d",&p1,&p2);
  53. printf("%d\n",dis[p1]+dis[p2]-*dis[lca(p1,p2)]);
  54. }
  55. return ;
  56. }

也可以记录g[x][i],则不必减去多余的。

事实证明在一些简单的树上路径问题上,倍增比链剖更有优势。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int maxn=;
  6. struct edge{int v,from,w;}e[maxn*];
  7. int n,first[maxn],deep[maxn],f[maxn][],g[maxn][],v[maxn],tot,lca,q;
  8. void insert(int u,int v,int w)
  9. {tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
  10. void dfs(int x,int fa)
  11. {
  12. for(int i=;(<<i)<=deep[x];i++)
  13. {
  14. f[x][i]=f[f[x][i-]][i-];
  15. g[x][i]=g[x][i-]+g[f[x][i-]][i-];
  16. }
  17. for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa)
  18. {
  19. int y=e[i].v;
  20. f[y][]=x;
  21. deep[y]=deep[x]+;
  22. g[y][]=e[i].w;
  23. dfs(y,x);
  24. }
  25. }
  26. int find(int x,int y)
  27. {
  28. int ans=;
  29. if(deep[x]<deep[y])swap(x,y);
  30. int d=deep[x]-deep[y];
  31. for(int i=;(<<i)<=deep[x];i++)
  32. if((<<i)&d){ans+=g[x][i];x=f[x][i];}
  33. if(x==y)return ans;
  34. for(int i=;i>=;i--)
  35. if((<<i)<=deep[x]&&f[x][i]!=f[y][i])
  36. {
  37. ans+=g[x][i]+g[y][i];
  38. x=f[x][i];y=f[y][i];
  39. }
  40. lca=f[x][];
  41. return ans+g[x][]+g[y][];
  42. }
  43. int main()
  44. {
  45. scanf("%d%d",&n,&q);
  46. for(int i=;i<n;i++)
  47. {
  48. int u,v,w;
  49. scanf("%d%d%d",&u,&v,&w);
  50. insert(u,v,w);
  51. insert(v,u,w);
  52. }
  53. dfs(,-);
  54. for(int i=;i<=q;i++)
  55. {
  56. int u,v;
  57. scanf("%d%d",&u,&v);
  58. printf("%d\n",find(u,v));
  59. }
  60. return ;
  61. }

【BZOJ】1602:[Usaco2008 Oct]牧场行走的更多相关文章

  1. bzoj 1602 [Usaco2008 Oct]牧场行走(LCA模板)

    1602: [Usaco2008 Oct]牧场行走 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 379  Solved: 216[Submit][Sta ...

  2. BZOJ 1602: [Usaco2008 Oct]牧场行走( 最短路 )

    一棵树..或许用LCA比较好吧...但是我懒...写了个dijkstra也过了.. ---------------------------------------------------------- ...

  3. BZOJ——1602: [Usaco2008 Oct]牧场行走 || 洛谷—— P2912 [USACO08OCT]牧场散步Pasture Walking

    http://www.lydsy.com/JudgeOnline/problem.php?id=1602 || https://www.luogu.org/problem/show?pid=2912 ...

  4. BZOJ 1602: [Usaco2008 Oct]牧场行走 倍增裸题

    Description N头牛(2<=n<=1000)别人被标记为1到n,在同样被标记1到n的n块土地上吃草,第i头牛在第i块牧场吃草. 这n块土地被n-1条边连接. 奶牛可以在边上行走, ...

  5. LCA || BZOJ 1602: [Usaco2008 Oct]牧场行走 || Luogu P2912 [USACO08OCT]牧场散步Pasture Walking

    题面:[USACO08OCT]牧场散步Pasture Walking 题解:LCA模版题 代码: #include<cstdio> #include<cstring> #inc ...

  6. BZOJ 1602 [Usaco2008 Oct]牧场行走 dfs

    题意:id=1602">链接 方法:深搜暴力 解析: 这题刚看完还有点意思,没看范围前想了想树形DP,只是随便画个图看出来是没法DP的,所以去看范围. woc我没看错范围?果断n^2暴 ...

  7. BZOJ 1602 USACO2008 Oct 牧场行走

    翻翻吴大神的刷题记录翻到的... 乍一看是一个树链剖分吓瓜我...难不成吴大神14-10-28就会了树剖?orz... 再一看SB暴力都可过... 然后一看直接树上倍增码个就好了... 人生真是充满着 ...

  8. bzoj 1602: [Usaco2008 Oct]牧场行走【瞎搞】

    本来想爆手速写个树剖,然而快下课了就手残写了了个n方的短小-- 暴力把查询的两个点中深的一个跳上来,加上边权,然后一起跳加边权就行了 #include<iostream> #include ...

  9. 1602: [Usaco2008 Oct]牧场行走

    1602: [Usaco2008 Oct]牧场行走 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1211  Solved: 616 [Submit][ ...

  10. 【BZOJ】1602: [Usaco2008 Oct]牧场行走(lca)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1602 一开始以为直接暴力最短路,但是n<=1000, q<=1000可能会tle. 显然 ...

随机推荐

  1. 深入理解Java对象序列化(转载)

    原文地址:http://developer.51cto.com/art/201202/317181.htm 1. 什么是Java对象序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般 ...

  2. Java核心技术点之接口

    1. 为什么使用接口 Java中的接口是一组对需求的描述.接口通过声明接口方法来对外宣布:“要想具有XX功能,就得按我说的做(即实现接口方法).” 而接口的实现类通过实现相应接口的方法来宣布:“我已经 ...

  3. lintcode-191-乘积最大子序列

    191-乘积最大子序列 找出一个序列中乘积最大的连续子序列(至少包含一个数). 样例 比如, 序列 [2,3,-2,4] 中乘积最大的子序列为 [2,3] ,其乘积为6. 标签 子数组 领英 动态规划 ...

  4. lintcode-138-子数组之和

    138-子数组之和 给定一个整数数组,找到和为零的子数组.你的代码应该返回满足要求的子数组的起始位置和结束位置 注意事项 There is at least one subarray that it' ...

  5. LintCode-7-二叉树的序列化和反序列化

    二叉树的序列化和反序列化 设计一个算法,并编写代码来序列化和反序列化二叉树.将树写入一个文件被称为"序列化",读取文件后重建同样的二叉树被称为"反序列化". 如 ...

  6. WinForm连续点击按钮只打开一次窗体

    许多朋友,学习C#时,制作WinForm小程序总会有一个问题,如果我们在父窗体设置的是点击一个按钮,打开一个子窗体,连续点击总会连续出现一样窗体,可是我们有时只想打开一次窗体,怎么办? 呵呵,我来方法 ...

  7. Sass的命令编译

    [Sass]命令编译 命令编译是指使用你电脑中的命令终端,通过输入 Sass 指令来编译 Sass.这种编译方式是最直接也是最简单的一种方式.因为只需要在你的命令终端输入: 单文件编译: sass & ...

  8. PHP给图片添加图片水印

    涉及到的函数: 1.file_get_contents():用于将文件的内容读入到一个字符串中的首选方法.如果操作系统支持,还会使用内存映射技术来增强性能. 2.list():list() 函数用于在 ...

  9. tc:逼良为娼

    tc的学习原来是想着直接从用户态学习的,但是万万没想到哇,qdisc class两个概念直接把我给搞晕了,直接看代码吧 调用:tc qdisc add dev tap0 root handle 1: ...

  10. Spring编程式事务管理及声明式事务管理

    本文将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. Spring 事务属性分析 事务管理 ...