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. scikit-learn入门导航

    scikit-learn是一个非常强大的机器学习库, 提供了很多常见机器学习算法的实现. scikit-learn可以通过pip进行安装: pip install -U scikit-learn 不过 ...

  2. Shell 实例:备份最后一天内所有修改过的文件

    在一个"tarball"中(经过 tar 和 gzip 处理过的文件)备份最后 24 小时之内当前目录下所有修改的文件. 程序代码如下: #!/bin/bash BACKUPFIL ...

  3. SQL partition by的用法

    今天群里看到一个问题,在这里概述下:查询出不同分类下的最新记录.一看这不是很简单的么,要分类那就用Group By; 要最新记录就用Order By呗.然后在自己的表中试着做出来: 首先呢我把表中的数 ...

  4. MVC 【Razor 视图引擎】基础操作 --页面跳转,传值,表单提交

    ASPX  与  Razor  仅仅是视图不一样. 新建项目----ASP.NET MVC 4 Web 应用程序------选择模板(空).视图引擎(Razor ) 1.视图中 c# 代码  与 HT ...

  5. spark基本概念及入门

    spark spark背景 什么是spark Spark是一种快速.通用.可扩展的大数据分析引擎,2009年诞生于加州大学伯克利分校AMPLab,2010年开源,2013年6月成为Apache孵化项目 ...

  6. Python 练习:简单的购物车(二)

    优化了上一个购物车程序:http://www.cnblogs.com/klvchen/p/8577269.html #输入工资salary = input("Please input you ...

  7. react的生命周期需要知道的。

    有关React生命周期: 1.组件生命周期的执行次数是什么样子的??? 只执行一次: constructor.componentWillMount.componentDidMount 执行多次:ren ...

  8. 基础篇|一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

  9. 使用过AsyncTask、EventBus、Volley以及Retrofit,必须好好了解handler运行机制

    我们都知道在UI线程中不能进行耗时操作,例如数据读写.网络请求.Android 4.0开始,在主线程中进行网络请求甚至会抛出Android.os.NetworkOnMainThreadExceptio ...

  10. etcd raft如何实现Linearizable Read

    Linearizable Read通俗来讲,就是读请求需要读到最新的已经commit的数据,不会读到老数据. 对于使用raft协议来保证多副本强一致的系统中,读写请求都可以通过走一次raft协议来满足 ...