树——倍增LCA
与正文无瓜的前言
身为一个高一才开始学的OIER,现在才开始恶补模板,感觉今年就要退役了。
不想刷题了滚过来写写博客<-------极端危险的思想。
引入
LCA(Lowest Common Ancestors),即最近公共祖先,听名字就知道这是与树上两个节点有关的东西。
它的定义就是两个点最近的公共祖先(废话),同时它也是树上一个节点到另一个节点的最短路中经过的深度最小的点。
如图,2就是8与9的最近公共祖先,7就是10和12的最近公共祖先。

那么LCA有什么用呢?
举个例子,我们可以利用LCA在O(1)的时间复杂度内求出树上两点u,v的最短距离。这里用dep表示节点的深度。
dis(u,v)=dep(u)+dep(v)-2*dep(LCA(u,v));
所以能快速求出LCA就可以快速求出两点间的距离。当然LCA还有其它作用,这里就不再赘述了(其实我并不知道)。
正文
我们来想一下一般的LCA求法。
对于任意两个节点u,v,如果我们一开始让它们同时向上寻找祖先,因为它们深度可能不同,其中深度较低的点就会向上走过头。
就像这样:

所以我们先让深度较深的点先向上走,走到与另一个点深度相同时,两个点再肩并肩向上走,找到第一个公共祖先为止。


而用倍增求LCA的方法也跟这个差不多,只不过不是一步一步向上走,而是先预处理出每个点向上走2^k步到达的节点,再向上飞。
设fa[i][j]为i节点向上走2^j步到达的节点,那么fa[i][j]可以这么转移:fa[i][j]=fa[ fa[i][j-1] ][j-1]转移过来。
这里介绍两种预处理的方式。
一种是一边遍历树一边处理,代码如下:
void dfs(int x,int f)
{
dep[x]=dep[fa[x][]=f]+;
for(int j=;j<=;j++)
fa[x][j]=fa[fa[x][j-]][j-];
for(int i=info[x];i;i=nex[i])if(v[i]!=f)dfs(v[i],x);
}
另一种是先遍历,然后处理,代码:
void dfs(int x,int f)
{
dep[x]=dep[fa[x][]=f]+;
for(int i=info[x];i;i=nex[i])if(v[i]!=f)dfs(v[i],x);
}
void pre()
{
dfs(,);
for(int j=;j<=LOG;j++)for(int i=;i<=n;i++)
fa[i][j]=fa[fa[i][j-]][j-];
}
预处理完后,我们就可以让深度较深的节点快速的与另一个节点会和,然后比翼双飞

直接给出代码和注解:
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int delta=dep[x]-dep[y];
for(int i=LOG;i>=;i--)
if(delta&(<<i))x=fa[x][i];//将delta转化为二进制,再用2^i凑出来
if(x==y)return x;
for(int i=LOG;i>=;i--)//用2^i凑距离,对于每个2^i只有可能被用一次,从大到小就是为了防止多用。
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];//如果相等就一起向上飞,会飞到公共祖先,但不是最近的
return fa[x][];
}
树——倍增LCA的更多相关文章
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- 树上第k小,可持久化线段树+倍增lca
给定一颗树,树的每个结点都有权值, 有q个询问,每个询问是 u v k ,表示u到v路径上第k小的权值是多少. 每个结点所表示的线段树,是父亲结点的线段树添加该结点的权值之后形成的新的线段树 c[ro ...
- 【BZOJ3123】[Sdoi2013]森林 主席树+倍增LCA+启发式合并
[BZOJ3123][Sdoi2013]森林 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整 ...
- bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s 内存限制:512.0MB 总提交次数:196 AC次数:65 平均分: ...
- 洛谷P2633 Count on a tree(主席树,倍增LCA)
洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...
- 洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)
洛谷题目传送门 闲话 这是所有LCT题目中的一个异类. 之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合. 只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要 ...
- 洛谷P2633 Count on a tree(主席树,倍增LCA,树上差分)
洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...
随机推荐
- isolate 通信
main.dart import 'package:flutter/material.dart'; import 'package:flutter_isolate/flutter_isolate.da ...
- Web应用的生命周期(客户端)
典型的一个Web应用的生命周期从用户在浏览器输入一串URL,或者单击一个链接开始(就是访问一个页面).而这个生命周期的结束就是我们关闭这个页面. 响应流程: 用户输入一个 URL(生命周期开始) 客户 ...
- 在angular 8中使用 less
在angular 6中使用 less 新项目 ng new [appname] --style less 已有的项目 修改 *.css 文件及引用处后缀名为 less并在 angular.json 文 ...
- 几种常见的Preference总结
DialogPreference共性 DialogPreference通用属性 说明 android:dialogIco 对话框的icon android:dialogLayout dialog的co ...
- mac环境下Android 反编译
连接地址: https://www.jianshu.com/p/3a305f32c4a3
- UCOSIII钩子函数
OSIdleTaskHook 空闲任务调用这个函数,可以用来让CPU进入低功耗模式 void OSIdleTaskHook (void) { #if OS_CFG_APP_HOOKS_EN > ...
- hash文件-对文件进行数字签名
(一)windows自带hash命令: certutil -hashfile D:\1.exe MD5 # md5的hash值为32位certutil -hashfile ...
- vue-element-admin 前端框架 使用感触
感触: 不搜不知道,一搜吓一跳!经常百度很重要. 美国有gitgub:https://github.com/search?q=vue-element-admin 中国有码云:https://gitee ...
- 【spark】spark应用(分布式估算圆周率+基于Spark MLlib的贷款风险预测)
注:本章不涉及spark和scala原理的探讨,详情见其他随笔 一.分布式估算圆周率 计算原理:假设正方形的面积S等于x²,而正方形的内切圆的面积C等于Pi×(x/2)²,因此圆面积与正方形面积之比C ...
- Android笔记(四十九) Android中的资源访问——asset
1.文件读取方式 AssetManager.open(String filename),返回的是一个InputSteam类型的字节流,这里的filename必须是文件,而不能是文件夹, ...