LCA就是最近公共祖先,比如

节点10和11的LCA就是8,9和3的LCA就是3。

我们这里讲一下用树上倍增来求LCA。

大家都可以写出暴力解法,两个节点依次一步一步往上爬,直到爬到了相同的一个节点。

二树上倍增就是对暴力的优化,改成了一次爬好几步。

具体怎么爬呢?就是两个点每次爬 2^j 步,而 j 满足的是两个点爬到的点不能相同,因为这样可能是公共祖先,但不一定是最近的。在这种条件下要使 j 尽可能的大。

举个例子,比如上图的节点7和8,当 j = 2 时,都爬到了节点 1,然而很显然这不是 LCA(7, 8),所以只能取 j = 1,7和8分别跳到3和4。然后发现3和4跳不了了,算法结束,答案就是3和4的父亲节点2。

还有一个小点,若两个点深度不同,只需让深的点往上跳到相同的深度就行。

接下来就开始写代码了。

先要预处理节点 i 跳 2^j 步跳到的点是什么。开一个数组fa[i][j],代表了节点i向上爬了2^j 步所到达的节点。那么递推式就是 fa[i][j] = fa[fa[i][j - 1]][j - 1]。

然后就直接可以求LCA了。

以洛谷的板子为例。传送门:https://www.luogu.org/problemnew/show/P3379

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 5e5 + ;
vector<int>v[maxn];
int dep[maxn], fa[maxn][],vis[maxn];
void dfs(int now) //预处理
{
vis[now] = ;
for(int i = ; ( << i) <= dep[now]; ++i)
fa[now][i] = fa[fa[now][i - ]][i - ];
for(int i = ; i < v[now].size(); ++i)
if(!vis[v[now][i]])
{
dep[v[now][i]] = dep[now] + ;
fa[v[now][i]][] = now; //就是v[now][i]的父亲now
dfs(v[now][i]);
}
}
int lca(int x, int y) //O(logn)
{
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; --i) //使x, y深度相同
if(dep[x] - ( << i) >= dep[y]) x = fa[x][i];
if(x == y) return x; //若两点正好重合,直接返回
for(int i = ; i >= ; --i)
if(fa[x][i] != fa[y][i])
{
x = fa[x][i]; y = fa[y][i];
}
return fa[x][]; //x的父亲节点就是x向上跳2^0步
}
int main()
{
int n, m, s; scanf("%d%d%d", &n, &m, &s);
for(int i = ; i < n; ++i)
{
int a, b; scanf("%d%d", &a, &b);
v[a].push_back(b); v[b].push_back(a);
}
dfs(s);
while(m--)
{
int a, b; scanf("%d%d", &a, &b);
printf("%d\n", lca(a, b));
}
return ;
}

时间复杂度是O(nlogn)。

LCA树上倍增的更多相关文章

  1. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  2. HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...

  3. 关于树论【LCA树上倍增算法】

    补了一发LCA,表示这东西表面上好像简单,但是细节真挺多. 我学的是树上倍增,倍增思想很有趣~~(爸爸的爸爸叫奶奶.偶不,爷爷)有一个跟st表非常类似的东西,f[i][j]表示j的第2^i的祖先,就是 ...

  4. LCA——树上倍增

    首先,什么是LCA? LCA:最近公共祖先 祖先:从当前点到根节点所经过的点,包括他自己,都是这个点的祖先 A和B的公共祖先:同时是A,B两点的祖先的点 A和B的最近公共祖先:深度最大的A和B的公共祖 ...

  5. 洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增

    倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ...

  6. LCA树上倍增求法

    1.LCA LCA就是最近公共祖先(Least common ancestor),x,y的LCA记为z=LCA(x,y),满足z是x,y的公共祖先中深度最大的那一个(即离他们最近的那一个)qwq 2. ...

  7. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  8. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  9. 两种lca的求法:树上倍增,tarjan

    第一种:树上倍增 f[x,k]表示x的2^k辈祖先,即x向根结点走2^k步达到的结点. 初始条件:f[x][0]=fa[x] 递推式:f[x][k]=f[ f[x][k-1] ][k-1] 一次bfs ...

随机推荐

  1. Scala函数与函数式编程

    函数是scala的重要组成部分, 本文将探讨scala中函数的应用. scala作为支持函数式编程的语言, scala可以将函数作为对象即所谓"函数是一等公民". 函数定义 sca ...

  2. python argparse(参数解析模块)

    这是一个参数解析,可以用它快捷的为你的程序生成参数相关功能 import argparse(导入程序参数模块) # 创建argparse对象,并将产品简要说明加入show = '程序说明' ===&g ...

  3. MyBatis从入门到放弃三:一对一关联查询

    前言 简单来说在mybatis.xml中实现关联查询实在是有些麻烦,正是因为起框架本质是实现orm的半自动化. 那么mybatis实现一对一的关联查询则是使用association属性和resultM ...

  4. 学Java的第17天。呃。。。今天有点奇葩

    神奇的老师在网上看到狗跳楼的视频然后就想到抛物线问题: 还是 属性和方法的调用: package sklx; public class Dog{ private float v = 30.0f; pr ...

  5. That Nice Euler Circuit(LA3263+几何)

    That Nice Euler Circuit Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu D ...

  6. char和string的不同点

    'a'是char, "a"是char string,这两者都是普通的字符和字符串,和C中没什么不同 值得注意的是后者包含两个字符,末尾有一个隐身的'\0' 而:string str ...

  7. 微信跳一跳Python辅助无需配置一键操作

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/8350329.html 邮箱:moyi@moyib ...

  8. JS--我发现,原来你是这样的JS:面向对象编程OOP[1]--(理解对象和对象属性类型)

    一.介绍 老铁们,这次是JS的面向对象的编程OOP(虽然我没有对象,心累啊,但是可以自己创建啊,哈哈). JS高程里第六章的内容,这章内容在我看来是JS中很难理解的一部分.所以分成三篇博客来逐个理清. ...

  9. 遇到了ImportError: libmysqlclient_r.so.16: cannot open shared object file: No such file or directory

    解决方法如下: 1. 通过命令查找libmysqlclient_r.so.16 在什么地方,一般是在/usr/lib64/mysql/下面 2. 做一个链接到/usr/lib64 下: ln -s / ...

  10. Android学习笔记----Java字符串MD5加密

    代码如下: /** * MD5单向加密,32位,用于加密密码,因为明文密码在信道中传输不安全,明文保存在本地也不安全 * * @param str * @return */ public static ...