LCA 算法是一个技巧性很强的算法。

十分感谢月老提供的模板。

这里我实现LCA是通过倍增,其实就是二进制优化。

任何一个数都可以有2的阶数实现

例如16可以由1 2 4 8组合得到

5可以由1 2 4 组合得到

便于读者理解 我放一道例题吧

Problem F: 挑战迷宫

Description

小翔和小明正在挑战一个神奇的迷宫。迷宫由n个房间组成,每个房间的编号为1~n,其中1号房间是他们俩初始位置,
所有房间一共由n-1条路连接,使得房间两两之间能够相互达到(构成一棵树),每条路的长度为Wi。
  每当小翔和小明都在房间时,他们的神奇手机就能显示两人的位置(两人分别在哪两个房间),现在想请聪明的ACMer
快速地算出他们之间的最短距离。

Input

  第一行输入整数n(0<n<=100000),表示迷宫有n个房间。
  接下来n-1行,每行输入3个整数u,v,w(1<=u,v<=n,u!=v,w<=10000),表示编号为u和v的房间之间有一条长为w的路。
  第n+1行输入整数m(0<m<=100000),表示有m次询问。
  接来下m行,每行输入2个整数u,v(1<=u,v<=n),表示小翔和小明当前所在房间的编号。

Output

对于每次询问的输出占一行,输出一个整数d表示小翔和小明之间的最短距离。

Sample Input

4
1 2 1
2 3 1
1 4 1
1
3 4

Sample Output

3

这是CSUST选拔赛的一题,表示当时不会LCA  菜的抠脚 (菜是原罪啊) 
注意这题时间为1S N为1e6 最短路肯定是不行的,复杂度不行。
n个点n-1条路 保证联通 其实就是每一个点到另外一个点有唯一的路径。
然后这就是一个非常非常裸的LCA。
 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector> using namespace std;
#define maxn 100010
struct node {
int x,y;
node(int x=,int y=):x(x),y(y){};
};
int rk[maxn],d[maxn],p[maxn][];
vector<node>a[maxn];
int n;
void dfs(int u,int fa,int cnt) {
rk[u]=cnt;
p[u][]=fa;
int len=a[u].size();
for (int i= ; i<len ; i++) {
int x=a[u][i].x;
if (x!=fa) {
d[x]=d[u]+a[u][i].y;
dfs(x,u,cnt+);
}
}
}
void lca() {
for (int i= ; i<=n ; i++ ) {
for (int j= ; (<<j)<=n ; j++) {
p[i][j]=-;
}
}
for (int j= ; (<<j)<=n ; j++) {
for (int i= ; i<=n ; i++) {
if (p[i][j-]!=-) p[i][j]=p[p[i][j-]][j-];
}
}
}
int query(int x,int y) {
if (rk[x]<rk[y]) swap(x,y );
int k;
for (k= ; (<<(+k))<=rk[x] ; k++);
for (int i= k; i>= ; i--) {
if (rk[x]-(<<i)>=rk[y]) x=p[x][i];
}
if (x==y) return x;
for (int i= k; i>= ; i--) {
if (p[x][i]!=- && p[x][i]!=p[y][i]){
x=p[x][i];
y=p[y][i];
}
}
return p[x][];
}
int main() {
int q,u,v,w;
while(scanf("%d", &n)!=EOF) {
for (int i = ; i < n; i++) {
scanf("%d%d%d", &u, &v, &w);
a[u].push_back(node(v, w));
a[v].push_back(node(u, w));
}
dfs(, -, );
lca();
scanf("%d", &q);
while (q--) {
scanf("%d%d", &u, &v);
printf("%d\n", d[u]+d[v]-*d[query(u, v)]);
}
}
return ;
}
其中DFS(int u,int fa, int cnt)
u表示当前节点 fa为他的父亲节点 cnt代表的是深度;
int rk[maxn]记录深度 d[maxn] 记录节点 p[maxn][30]记录父亲节点的位置
lca() 这个就是精髓所在了 第一步初始化p[i][j]=-1;
第二步就是二进制优化了 p[i][j]=p[p[i][j-1]][j-1] 表示i+2^j=i+2^(j-1)+2^(j-1)
前面都是预处理 第三步query(int x,int y) 求x,y的公共祖先。
先判断深度,然后算出2^k <rk[x] 的k的最大值。
if (rk[x]-(1<<i)>=rk[y]) x=p[x][i];将x的的深度向上回溯2^i
使之更接近rk[y]

for (int i= k; i>=0 ; i--) {
      if (p[x][i]!=-1 && p[x][i]!=p[y][i]){
         x=p[x][i];
         y=p[y][i];
      }
   }
   return p[x][0];

后面就是无脑回溯到公共祖先位置。

非常感谢月老的LCA倍增模板

以上就是我对LCA倍增算法的解析  
如果读者还有不懂可以留言给我。

LCA倍增算法的更多相关文章

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

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

  2. POJ 1330 Nearest Common Ancestors (LCA,倍增算法,在线算法)

    /* *********************************************** Author :kuangbin Created Time :2013-9-5 9:45:17 F ...

  3. 算法笔记--lca倍增算法

    算法笔记 模板: vector<int>g[N]; vector<int>edge[N]; ][N]; int deep[N]; int h[N]; void dfs(int ...

  4. LCA倍增算法的错误与模板

    先上我原来的错误的代码 type node=^link; link=record num:int64; next:node; end; var fa:..,..] of int64; dep:..] ...

  5. LCA 倍增算法模板

    . #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm&g ...

  6. LCA(最近公共祖先)之倍增算法

    概述 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4 在本篇中我们先介 ...

  7. LCA(倍增在线算法) codevs 2370 小机房的树

    codevs 2370 小机房的树 时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点, ...

  8. Lca 之倍增算法

    引入: 比如说要找树上任意两个点的路上的最大值.如果是一般的做法 会 接近o(n)的搜,从一个点搜到另一个点,但是如果询问多了复杂度就很高了. 然后我们会预处理.预处理是o(n²)的,询问是o(1)的 ...

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

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

随机推荐

  1. 腾讯云微计算实践:从Serverless说起,谈谈边缘计算的未来

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:黄文俊,腾讯云高级产品经理,曾经历过企业级存储.企业级容器平台等产品的架构与开发,对容器.微服务.无服务器.DevOps等都有浓厚兴趣. ...

  2. 插入排序实现&&选择排序实现

    萌新刚刚开始学习算法,第一步是学习排序,毕竟算法的四大块"排序,查找,图,字符串"里面,排序是第一位的(PS:今天才知道算法提供的只是一个程序编写思路,一直以为是一个函数,难怪传入 ...

  3. Java经典编程题50道之二十四

    有5个人坐在一起,问第5个人多少岁,他说比第4个人大2岁.问第4个人岁数,他说比第3个人大2岁. 问第三个人,他说比第2人大两岁.问第2个人, 说比第一个人大两岁.最后问第一个人,他说是10岁. 请问 ...

  4. MySQL体系结构及多实例

    MySQL客户端和服务器端模型 MySQL是一个典型C/S,服务器端与客户端两部分组成 服务器端程序  mysqld mysql自带的客户端(mysql mysqladmin  mysqldump等) ...

  5. 3.2 while 循环

    Python 编程中 while 语句用于循环执行程序,即在条件满足的情况下,循环执行某段代码.所以就需要在循环的代码块中设计一种使代码块循环执行一定次数后是while语句的条件不满足,从而中止whi ...

  6. POJ - 1321 dfs [kuangbin带你飞]专题一

    枚举行和列即可,当前已经放下cnt个棋子,当前已经搜索到第r行,如果 n - r + cnt  < k 直接退出,因为后面无法放下剩下的棋子. AC代码 #include<cstdio&g ...

  7. nodejs爬虫初试---superagent和cheerio

    前言 早就听过爬虫,这几天开始学习nodejs,写了个爬虫 demo ,爬取 博客园首页的文章标题.用户名.阅读数.推荐数和用户头像,现做个小总结. 使用到这几个点: 1.node的核心模块-- 文件 ...

  8. R实战 第三篇:数据处理

    在实际分析数据之前,必须对数据进行清理和转化,使数据符合相应的格式,提高数据的质量.数据处理通常包括增加新的变量.处理缺失值.类型转换.数据排序.数据集的合并和获取子集等. 一,增加新的变量 通常需要 ...

  9. 沉淀,再出发——在Ubuntu Kylin15.04中配置Hadoop单机/伪分布式系统经验分享

    在Ubuntu Kylin15.04中配置Hadoop单机/伪分布式系统经验分享 一.工作准备 首先,明确工作的重心,在Ubuntu Kylin15.04中配置Hadoop集群,这里我是用的双系统中的 ...

  10. 暴力破解MD5的实现(MapReduce编程)

    本文主要介绍MapReduce编程模型的原理和基于Hadoop的MD5暴力破解思路. 一.MapReduce的基本原理 Hadoop作为一个分布式架构的实现方案,它的核心思想包括以下几个方面:HDFS ...