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. 将Word表格中单元格中的文字替换成对应的图片

    示例 原文件结构: 替换后文档结构: 软件截图: 代码: using System;using System.Collections.Generic;using System.ComponentMod ...

  2. Spring mvc学习指南

    使用flash attribute(闪存传值) 在配置文件中添加<mvc:annotion-driven/> 在controller方法参数里面添加RedirectAttributes r ...

  3. java12 - 正则表达式

    正则表达式简介 常用搭配说明: ^a 表示这个位置只能是字母 a [1,2,3,4] 表示这个位置只能在 1,2,3,4 中取一个 [[a-z][A-Z]] 表示可以任意大小写字母 ([a-z]{1, ...

  4. python——Django项目模板

    views.py # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.shortcuts impor ...

  5. C语言老司机学Python (一)

    Python 版本:3.6.4 参考网上教程:http://www.runoob.com/python3/python3-basic-syntax.html 开始了啊. 干咱们这行的老规矩,学新语言的 ...

  6. HttpURLConnection发送请求

    每个 HttpURLConnection 实例都可用于生成单个请求,但是其他实例可以透明地共享连接到 HTTP 服务器的基础网络.请求后在 HttpURLConnection 的 InputStrea ...

  7. "No Python interpreter configured for the project " in Pycharm for python selenium

    自动化测试问题: pyCharm提示python Interpreter没有设置,点击configure Python Interpreter,进入Settings 在 Project Interpr ...

  8. VC6安装错误——Error Launching acmboot.exe

    因项目需要,我需要安装Microsoft Visual C++ Professional Version 6 SP5.但是在安装时运行安装目录下的setup.exe,出现Error Launching ...

  9. 【php】strtr与str_replace的区别

    strtr(string,from,to): 逐个字符开始替换,以from跟to中长度较较短的一个为准,例如: strtr("aidenliu","ai",&q ...

  10. Flex中的FusionCharts 3D柱形图

    1.3D柱形图源码 <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:f ...