LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法:

暴力向上:O(n)

每次将深度大的点往上移动,直至二者相遇

树剖:O(logn)

在O(2n)预处理重链之后,每次就将深度大的沿重链向上,直至二者在一条链上

tarjan_lca:离线O(n+m)

先记录所有的询问,对树进行一次dfs,对于搜索到的点u,先将点u往下搜,再将点u与父节点所在集合合并,之后对于它的所有询问(u,v),若v已被访问,那么找v所在集合的祖先e,则e就是u与v的lca

但我们今天要讲的是

倍增lca

所谓倍增,就是利用二进制将冗长的多个相同步骤合并,以实现加速转移的算法。
比如快速幂就是一个经典的例子,将多次乘法通过二进制合并

下面我们来讲讲如何利用倍增求LCA:
还记得上面的暴力算法吗?
暴力算法是最质朴的东西,却是所有高端操作的出发点,倍增就是这样。
我们只需要利用倍增,将往上移动的操作压缩,就能实现算法复杂度的优化

实现

我们设f[i][j]表示i节点的第2^j代祖先,这样f[i][0]就是i的父亲,而对于所有j>0,我们有
f[i][j] = f[f[i][j - 1]][j - 1]
怎么理解呢?
i节点的第2^(j - 1)代祖先的2^(j - 1)祖先就是i的第2^j代祖先
所以我们用O(nlogn)的时间就预处理出了f[][]数组

void dfs(int u,int fa){
dep[u] = dep[fa] + 1;
f[u][0] = fa;
for (int k = head[u]; k != -1; k = edge[k].next)
if (edge[k].to != fa)
dfs(edge[k].to,u);
}

求深度

void cal(){
for (int i = 1; (1<<i) <= N; i++)
for(int u = 1; u <= N; u++)
f[u][i] = f[f[u][i - 1]][i - 1];
}

预处理



求出了f数组,怎么求lca呢?
对于询问lca(u,v),不妨设u是其中深度较大的,我们先将u升到离v同样的深度,设需要向上移动d = dep[u] - dep[v]
我们把d看做二进制,那么我们只需对于其中所有的1进行操作就好了

比如说:
我们需要向上5次,即101,那么我们只需要向上转移100次和1次,这就刚好与f[i][2]和f[i][0]相对应

移到相同位置后,我们从二进制大到小枚举,当u和v祖先不同时,就向上转移,最后u的祖先就是lca
int lca(int u,int v){
if (dep[u] < dep[v]) swap(u,v);
int d = dep[u] - dep[v];
for (int i = 0; (1<<i) <= d; i++)
if ((1<<i) & d)
u = f[u][i];
if (u != v){
for (int i = (int)log(N); i >= 0; i--)
if (f[u][i] != f[v][i]){
u = f[u][i];
v = f[v][i];
}
return f[u][0];
}
else return u;
}

LCA的倍增算法的更多相关文章

  1. Lca 之倍增算法

    引入: 比如说要找树上任意两个点的路上的最大值.如果是一般的做法 会 接近o(n)的搜,从一个点搜到另一个点,但是如果询问多了复杂度就很高了. 然后我们会预处理.预处理是o(n²)的,询问是o(1)的 ...

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

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

  3. LCA(最近公共祖先)之倍增算法

    概述 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4 在本篇中我们先介 ...

  4. LCA倍增算法

    LCA 算法是一个技巧性很强的算法. 十分感谢月老提供的模板. 这里我实现LCA是通过倍增,其实就是二进制优化. 任何一个数都可以有2的阶数实现 例如16可以由1 2 4 8组合得到 5可以由1 2 ...

  5. 最近公共祖先 LCA 倍增算法

          树上倍增求LCA LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 ...

  6. 关于LCA的倍增解法的笔记

    emmmmm近日刚刚学习了LCA的倍增做法,写一篇BLOG来加强一下印象w 首先 何为LCA? LCA“光辉”是印度斯坦航空公司(HAL)为满足印度空军需要研制的单座单发轻型全天候超音速战斗攻击机,主 ...

  7. [模板]LCA的倍增求法解析

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  8. 【一个蒟蒻的挣扎】LCA (倍增)

    #include<cstdio> #include<iostream> #include<cstring> using namespace std; struct ...

  9. LCA树上倍增求法

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

随机推荐

  1. Hibernate三种状态的区分,以及save,update,saveOrUpdate,merge等的使用

    Hibernate的对象有3种状态,分别为:瞬时态(Transient). 持久态(Persistent).脱管态(Detached).处于持久态的对象也称为PO(Persistence Object ...

  2. 安装完.net core sdk 后部署 ASP.NET Core 出现错误502.5

    将项目升级到和sdk一样的版本 然后 命令行执行 iisreset

  3. Linux内核学习笔记(5)-- 进程调度概述

    进程调度程序是多任务操作系统的基础,它是确保进程能有效工作的一个内核子系统,负责决定哪个进程投入运行.何时运行以及运行多长时间.只有通过进程调度程序的合理调度,系统资源才能够最大限度地发挥作用,多进程 ...

  4. js页面跳转,url带url参数解决方案

    今天,在做一个项目的时候,向后端发送了一个Ajax请求,后端返回了一个字符串,告诉我未登录.那么我需要跳转到登录页面,同时告诉登录页面,登录成功后,需要跳回的url.也就是标题所说,url中的一个参数 ...

  5. Powershell按文件最后修改时间删除多余文件

    Powershell按文件最后修改时间删除多余文件 1. 删除目录内多余文件,目录文件个数大于$count后,按最后修改时间倒序排列,删除最旧的文件. Sort-Object -Property La ...

  6. KETTLE:mongdb与mysql互传数据

    注:部分内容引用了 http://blog.sina.com.cn/s/blog_4ac9f56e0101g881.html 1.mongodb传数据到mysql 1)在kettle中,mongodb ...

  7. Asphalting Roads(翻译!)

    Description City X consists of n vertical and n horizontal infinite roads, forming n × n intersectio ...

  8. Scrum立会报告+燃尽图(十月十四日总第五次):前期宣传工作进行中

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2195 Scrum立会master:段晓睿 一.小组介绍 组长:付佳 组员 ...

  9. Hexo博客搭建全解

    [原创,转载请附网址:http://dongshuyan.top] 欢迎来到莫与的博客,第一篇记录了一下怎么写一篇博客,以方便之后写博客~ #从配置说起下载安装Git与Node.js略过 1.安装he ...

  10. 使用Logstash同步数据至Elasticsearch,Spring Boot中集成Elasticsearch实现搜索

    安装logstash.同步数据至ElasticSearch 为什么使用logstash来同步,CSDN上有一篇文章简要的分析了以下几种同步工具的优缺点:https://blog.csdn.net/la ...