树——倍增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小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...
随机推荐
- iOS - 外加字体(只需三步-教你轻松实现)
外加字体 1.首先info.plist中加入属性Fonts provided by application,在item 0 处填写导入的ttf文件名 eg: <key>UIAppFonts ...
- Manjaro 安装笔记
双系统基本知识 [折腾日记]win10 ,ubuntu双系统安装避坑指南 Windows 下安装 Ubuntu 双系统(更新) rEFInd 总结注意点: 制作U盘启动盘一开始使用的是 Ulrstro ...
- Part_one:Redis第一次接触
1.redis学习 数据默认写入到内存,如果断电,服务器宕机,redis进程挂掉,数据会丢失. selenium操作浏览器时,要注意浏览器资源释放,方式内存泄露,崩溃 mysql是文件型数据库,默认持 ...
- elementui switch 开关,点击确认按钮后在进行开关
<el-table-column label="上头条" align="center"> <template slot-scope=" ...
- JAVA基础之ServletContext对象
个人理解: ServletContext类似字节码文件对象,在web创建的时候就自动生成了,并且是唯一的,跟随着项目和服务器共存亡了.通过这个对象,我们可以向里面存数据(键值对),也可以通过别的Se ...
- JavaScript常用数组操作方法,包含ES6方法
一.concat() concat() 方法用于连接两个或多个数组.该方法不会改变现有的数组,仅会返回被连接数组的一个副本. var arr1 = [1,2,3]; var arr2 = [4,5]; ...
- iOS配置TARGETS
说一下背景 自从这个项目不死不活的迭代了2年,从项目搭建到现在,一直都是自己在开发和维护,所以项目结构非常清晰,但是之前的水平写的代码现在看来也是惨不忍睹,不过本人比较懒,也就没有考虑过重构的事情 - ...
- IDEA中导入Maven模块
IDEA中导入Maven模块方式有二种: 1)批量添加,不可添加文件夹 2)单个添加,可添加任意文件
- angularcli 第三篇(数据循环*ngFor、条件判断*ngIf)
1.数据循环 *ngFor (1)普通循环 <ul> <li *ngFor = "let item of list" > {{ item }} </l ...
- github markdown语法及使用
历史 Markdown是一种轻量级标记语言,创始人为约翰·格鲁伯(英语:John Gruber).它允许人们"使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档 ...