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. 验证SQLServer死锁进程

    SELECT '现在没有阻塞和死锁信息' AS message -- 循环开始WHILE @intCounter <= @intCountProperties BEGIN-- 取第一条记录 SE ...

  2. OSI网络模型

    OSI中的层 功能 TCP/IP协议族 应用层         文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 表示层         数 ...

  3. REST&RESTFUL

    REST(表征性状态传输,Representational State Transfer)指的是一组架构约束条件和原则.是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格 ...

  4. 一个逼格很低的appium自动化测试框架

    Github地址: https://github.com/wuranxu 使用说明 1. 安装配置Mongo数据库 下载地址 mongo是用来存放元素定位的,截图如下: 通过case_id区分每个ca ...

  5. Mac上使用selenium自动运行chrome

    一.用我们的老朋友pip把selenium装好 pip install selenium 二.用webdriver.Chrome启动Chrome浏览器 from selenium import web ...

  6. 【Unity3D】Unity3D开发《我的世界》之三、创建一个Chunk

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/unity_minecraft_03.html 一.引入int类型的Vector3 我们都知道Unity3D里Vec ...

  7. mysql学习笔记02 表的操作

    创建数据表create  table table_name(//定义表的列的结构)创建表 先分析需要保存的实体数据,荣有哪些属性,这些属性应该有哪些属性列的定义 列名 列的数据类型 {} 进行表操作时 ...

  8. 【php】curl常见的错误号和解释

    curl 错误代码列表 CURLE_UNSUPPORTED_PROTOCOL (1) – 您传送给 libcurl 的网址使用了此 libcurl 不支持的协议. 可能是您没有使用的编译时选项造成了这 ...

  9. Flex读取txt文件中的内容(二)

    Flex读取txt文件中的内容 自动生成的文件 LoadTxt-app.xml: <?xml version="1.0" encoding="utf-8" ...

  10. linux下驱动模块化编译,动态加载以及卸载

    步骤:: 1.编写first_driver_hello.c文件,将其放在/linux2.6.32/drivers/char路径下: 2.在/linux2.6.32/drivers/cha/Kconfi ...