树——倍增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小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...
随机推荐
- mysql 数据库 规范
目录 mysql 数据库 规范 基础规范 命名规范 表设计规范 字段设计规范 索引设计规范 SQL编写规范 行为规范 mysql 数据库 规范 基础规范 必须使用InnoDB存储引擎 解读:支持事务. ...
- Django ORM整理
字段类型 # 自增长 Auto = models.AutoField() BigAuto = models.BigAutoField() # 二进制 Binary = models.BinaryFie ...
- aapt&adb笔记
aapt 查看安装包信息aapt list apk路径* aapt list xxx/app-debug.apk 查看apk文件信息并保存到本地(> 重定向符) * aapt list xx/a ...
- springboot学习入门简易版五---springboot2.0整合jsp(11)
springboot对jsp支持不友好,内部tomcat对jsp不支持,需要使用外部tomcat,且必须打包为war包. 1 创建maven项目 注意:必须为war类型,否则找不到页面. 且不要把js ...
- python之编码与解码、is 与==的区别
一.编码与解码 编码的过程其实就是采用一定的编码格式将unicode字符转换成str字符的过程 非ASCII码字符按字节为单位被编码成十六进制转义字符 解码采用的编码格式跟设置和环境有关 ascii ...
- 【HCIA Gauss】学习汇总-数据库管理(数据库基本概念)-3
数据库:操作系统文件或磁盘数据块的集合数据库实例: 指操作系统中一系列进程以及为这些进程分配的内存块 通常来说一个数据库实例对应着一个数据库[数据库实例是访问数据的通道] 多实例:利用多实例 可以充分 ...
- kubernetes 基本概念和资源对象汇总
kubernetes 基本概念和知识点脑图 基本概念 kubernetes 中的绝大部分概念都抽象成kubernets管理的资源对象,主要有以下类别: Master : Master节点是kubern ...
- Mongodb Sharding 集群配置
mongodb的sharding集群由以下3个服务组成: Shards Server: 每个shard由一个或多个mongod进程组成,用于存储数据 Config Server: 用于存储集群的M ...
- netty websocket
1 全局保存websocket的通道 NettyConfig.java public class NettyConfig { public static ChannelGroup group = n ...
- xinetd配置文件
xinetd是一个超级守护进程xinetd即extended internet daemon,xinetd是新一代的网络守护进程服务程序,又叫超级Internet服务器.经常用来管理多 种轻量级Int ...