【简介】

解决LCA问题的倍增法是一种基于倍增思想的在线算法。

【原理】

原理和同样是使用倍增思想的RMQ-ST 算法类似,比较简单,想清楚后很容易实现。

对于每个节点u , ancestors[u][k] 表示 u 的第2k个祖先是谁。很容易就想到递推式: ancestors[j][i] = ancestors[ancestors[j][i - 1]][i - 1];  根据二进制原理,理论上 u 的所有祖先都可以根据ancestors数组多次跳转得到,这样就间接地记录了每个节点的祖先信息。
     查询LCA(u,v)的时候:
         (一)u和v所在的树的层数如果一样,令u'=u。否则需要平衡操作(假设u更深),先找到u的一个祖先u', 使得u'的层数和v一样,此时LCA(u,v)=LCA(u',v) 。证明很简单:如果LCA(u,v)=v , 那么u'一定等于v ;如果LCA(u,v)=k ,k!=v ,那么k 的深度一定小于 v , u、u'、v 一定在k的子树中;综上所述,LCA(u,v)=LCA(u',v)一定成立。

(二)此时u' 和 v 的祖先序列中一开始的部分一定有所重叠,重叠部分的最后一个元素(也就是深度最深,与u'、v最近的元素)就是所求的LCA(u,v)。这里ancestors数组就可以派上用场了。找到第一个不重叠的节点k,LCA(u,v)=ancestors[k][0] 。 找k的过程利用二进制贪心思想,先尽可能跳到最上层的祖先,如果两祖先相等,说明完全可以跳小点,跳的距离除2,这样一步步跳下去一定可以找到k。

【hdu 2586】

需要注意的是超界的处理。

 #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
int n,m;
struct edge
{
int d,v,next;
edge(){}
edge(int _d,int _v,int _next)
{
d=_d;v=_v;next=_next;
}
}data[];
int map[];
int pool;
void addedge(int s,int e,int v)
{
int t=map[s];
data[pool++]=edge(e,v,t);
map[s]=pool-;
}
int ANCLOG;
int depth[];
int ifv[];
int dis[];
int anc[][];
void dfs(int cur,int dep)
{
ifv[cur]=;
depth[cur]=dep;
int p=map[cur];
while (p!=-)
{
if (!ifv[data[p].d])
{
dis[data[p].d]=dis[cur]+data[p].v;
anc[data[p].d][]=cur;
dfs(data[p].d,dep+);
}
p=data[p].next;
}
}
void initLCA()
{
for (int k=;k<ANCLOG;++k)
for (int i=;i<n;++i)
{
if (anc[i][k-]==-) continue;
anc[i][k]=anc[anc[i][k-]][k-];
}
}
int getLCA(int u,int v)
{
if (depth[u]<depth[v]) swap(u,v);
for (int k=ANCLOG;k>=;--k)
{
if (anc[u][k]==-) continue;
if (depth[anc[u][k]]>=depth[v])
{
u=anc[u][k];
if (depth[u]==depth[v]) break;
}
}
if (u==v) return u;
for (int k=ANCLOG;k>=;--k)
{
if (anc[u][k]==-) continue;
if (anc[u][k]!=anc[v][k])
{
u=anc[u][k];
v=anc[v][k];
}
}
return anc[u][];
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
pool=;
memset(anc,-,sizeof anc);
memset(map,-,sizeof map);
memset(ifv,,sizeof ifv);
scanf("%d%d",&n,&m);
ANCLOG=(int)(log(n)/log(2.0));
int s,e,v;
for (int i=;i<n-;++i)
{
scanf("%d%d%d",&s,&e,&v);
addedge(s-,e-,v);
addedge(e-,s-,v);
}
dis[]=;
dfs(,);
initLCA();
for (int i=;i<m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
--u;--v;
int k=getLCA(u,v);
k=dis[u]+dis[v]-*dis[k];
printf("%d\n",k);
}
}
}

最近公共祖先 LCA 倍增法的更多相关文章

  1. luogu3379 【模板】最近公共祖先(LCA) 倍增法

    题目大意:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 整体步骤:1.使两个点深度相同:2.使两个点相同. 这两个步骤都可用倍增法进行优化.定义每个节点的Elder[i]为该节点的2^k( ...

  2. 【lhyaaa】最近公共祖先LCA——倍增!!!

    高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...

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

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

  4. LCA(最近公共祖先)——LCA倍增法

    一.前人种树 博客:最近公共祖先 LCA 倍增法 博客:浅谈倍增法求LCA 二.沙场练兵 题目:POJ 1330 Nearest Common Ancestors 代码: const int MAXN ...

  5. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

  6. 最近公共祖先(LCA)的三种求解方法

    转载来自:https://blog.andrewei.info/2015/10/08/e6-9c-80-e8-bf-91-e5-85-ac-e5-85-b1-e7-a5-96-e5-85-88lca- ...

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

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

  8. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  9. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

随机推荐

  1. 一种通过HTTP传文件出网的姿势

    在外网机器上运行文件服务接收服务 root@kali:~/pentest-script/FileTransfer/HttpServer# python3 SimpleHttpUpload.py Ser ...

  2. Spring注解@Resource和@Autowired区别对比、spring扫描的默认bean的Id、程序获取spring容器对象

    -------------------------注解扫面的bean的ID问题-------------------------- 0.前提需要明白注解扫描出来的bean的id默认是类名首字母小写,当 ...

  3. 【DeepLearning学习笔记】Coursera课程《Neural Networks and Deep Learning》——Week2 Neural Networks Basics课堂笔记

    Coursera课程<Neural Networks and Deep Learning> deeplearning.ai Week2 Neural Networks Basics 2.1 ...

  4. Vim中的键映射【转】

    转自:http://www.cnblogs.com/softwaretesting/archive/2011/09/28/2194515.html http://www.pythonclub.org/ ...

  5. centos 快捷键

    centos 快捷键大全 时间:2013-02-23 14:54来源:blog.csdn.net 举报 点击:225次 新手通常会不太习惯GNOME或KDE的界面操作,不过还好,LINUX的快捷键大多 ...

  6. gcc -rpath 指定动态库路径

    gcc -rpath 指定动态库路径 http://blog.csdn.net/v6543210/article/details/44809405

  7. 根据节点解析xml

    config.xml文件如下: <?xml version="1.0" encoding="gb2312" ?> <root> < ...

  8. cookies保存购物车数据的编码问题(pickle和base64)

    在保存cookies时,如果存在着中文字符,cookies保存会报错.所以需要对数据进行编码. 通常cookies的保存都是以Base64来保存.所以先要对数据编码成bytes,再编码成base64字 ...

  9. HDU 3669 Cross the Wall(斜率DP+预处理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3669 题目大意:有n(n<=50000)个矩形,每个矩形都有高和宽,你可以在墙上最多挖k个洞使得 ...

  10. 转载:【知乎Live】狼叔:如何正确的学习Node.js

    [知乎Live]狼叔:如何正确的学习Node.js 作者:狼叔:i5ting 原文链接:https://i5ting.github.io/How-to-learn-node-correctly/