倍增求LCA算法详解
算法介绍:
看到lca问题(不知道lca是什么自(bang)行(ni)百度),不难想到暴力的方法;
先把两点处理到同一深度,再让两点一个一个祖先往上找,直到找到一个相同的祖先;
这么暴力的话,时间复杂度基本上是$ o(n) $;
而观察一下暴力的过程,就会发现,其实一个一个祖先往上找效率非常的低,有没有能优化这一过程的方法呢?这时,强大的倍增就出现了,能够把暴力优化到$ o(log(n)) $;
倍增,简单说就是把一步一步跳替换成每次跳$ 2^i $个祖先;
做法:
先预处理出每个点的深度(dfs或bfs),以及跳$ 2^i $个祖先后所在的位置(fa[i][j]表示第i个点跳$ 2^j $个祖先后的位置,再递推);
然后同理暴力,先把两点跳到同一深度(也用倍增),每次跳$ 2^i $个祖先,判断是否相等,如果相等就不跳(原因见易错点),否则跳;
难点:
1、递推时方程为fa[i][j]=fa[fa[i][j-1]][j-1],因为i跳$ 2^j $个祖先后所在的位置等于i连跳两次$ 2^{j-1} $个祖先后所在的位置;
2、递推时,j先扫1到20,i再扫1到n,因为每次更新f[i][j]要用到另外的位置跳$ 2^{j-1} $个祖先后所在的位置;
3、两个点跳的时候,如果相等,是不能直接输出的,有可能跳过头,就不是最近的公共祖先了;
4、每次读进来的边要存两次(树是无向图),同理,邻接表的数组也要开两倍长;
相关题目
1、洛谷p3379
模板题,放上丑陋的代码
- #include<cstdio>
- using namespace std;
- const int MAXN=;//两倍长
- int tot,n,m,s,first[MAXN],last[MAXN],next[MAXN],to[MAXN],depth[MAXN],fa[MAXN][];
- //depth是每个点的深度,fa[i][j]表示第i个点跳2^j个祖先后的位置
- bool visited[MAXN];
- inline int read()//快读
- {
- int s=,w=;
- char ch=getchar();
- while(ch<=''||ch>''){if(ch=='-')w=-;ch=getchar();}
- while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
- return s*w;
- }
- void swap(int &x,int &y)
- {
- int k=x;
- x=y;
- y=k;
- }
- void add(int x,int y)//古董邻接表
- {
- ++tot;
- if(first[x]==) first[x]=tot; else next[last[x]]=tot;
- last[x]=tot;
- to[tot]=y;
- }
- void dfs(int now,int dep,int fat)//深搜求深度
- {
- if(visited[now]) return;
- visited[now]=true;
- depth[now]=dep;
- fa[now][]=fat;//要记得fa[i][0]存i的父亲(跳一(2^0)个祖先)
- for(int i=first[now];i;i=next[i])
- {
- dfs(to[i],dep+,now);
- }
- }
- int lca(int x,int y)
- {
- if(depth[x]<depth[y]) swap(x,y);
- for(int i=;i>=;--i)
- if(fa[x][i]!=&&depth[fa[x][i]]>=depth[y])
- {
- x=fa[x][i];
- }
- if(x==y) return x;
- for(int i=;i>=;--i)
- if(fa[x][i]!=&&fa[y][i]!=&&fa[x][i]!=fa[y][i])
- {
- x=fa[x][i];
- y=fa[y][i];
- }
- return fa[x][];
- }
- int main()
- {
- n=read();
- m=read();
- s=read();
- for(int i=;i<=n-;++i)
- {
- int x,y;
- x=read();
- y=read();
- add(x,y);
- add(y,x);
- }
- dfs(s,,);
- for(int j=;j<=;++j)
- for(int i=;i<=n;++i)
- fa[i][j]=fa[fa[i][j-]][j-];
- for(int i=;i<=m;++i)
- {
- int x;
- int y;
- x=read();
- y=read();
- printf("%d\n",lca(x,y));
- }
- return ;
- }
倍增求LCA算法详解的更多相关文章
- [学习笔记] 树上倍增求LCA
倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. ...
- [算法]树上倍增求LCA
LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4 ...
- HDU6031 Innumerable Ancestors 倍增 - 题意详细概括 - 算法详解
去博客园看该题解 题目 查看原题 - HDU6031 Innumerable Ancestors 题目描述 有一棵有n个节点的有根树,根节点为1,其深度为1,现在有m个询问,每次询问给出两个集合A和B ...
- kmp算法详解
转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector ...
- [转] KMP算法详解
转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的K ...
- 【转】AC算法详解
原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...
- KMP算法详解(转自中学生OI写的。。ORZ!)
KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...
- EM算法详解
EM算法详解 1 极大似然估计 假设有如图1的X所示的抽取的n个学生某门课程的成绩,又知学生的成绩符合高斯分布f(x|μ,σ2),求学生的成绩最符合哪种高斯分布,即μ和σ2最优值是什么? 图1 学生成 ...
随机推荐
- 【ABAP系列】SAP ABAP 刷新SCREEN的方法
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 刷新SCREE ...
- JDK8新特性之一Lambda
JDK8的新特性之一Lambda能将函数作为方法里面的参数使用. /** * JDK8新特性Lambda */ public class Test { public static void main( ...
- pandas中.value_counts()的用法
原文链接:https://www.jianshu.com/p/f773b4b82c66 value_counts()是一种查看表格某列中有多少个不同值的快捷方法,并计算每个不同值有在该列中有多少重复值 ...
- mysql数据库负载均衡高可用之主从、主主备份,实时同步
一:MySQL Replication 什么是MySQL Replication Replication可以实现将数据从一台数据库服务器(master)复制到一或多台数据库服务器(slave) 默认情 ...
- 【Linux内核】编译与配置内核(arm)
ARM平台使用的内核 (1)清除原有的配置与中间文件 make distclean(2)配置内核 make menuconfig ARCH=arm(3)编译内核 make uImage ARCH=ar ...
- CentOS7中MySQL跨机器数据迁移
1.概况 在CentOS7环境下,使用命令方式将MySQL数据从源端主机迁移到目标端主机上. 2.迁移全部数据库 1)源端备份: [root@hadoop102 /]# mysqldump -u ro ...
- 通过编写串口助手工具学习MFC过程--(十一)弹出模态型对话框
通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...
- Redis主从架构核心原理
Redis-Cluster工作原理: redis集群内置了16384个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果 ...
- 使用PHPWord生成word文档
有时我们需要把网页内容保存为Word文档格式,以供其他人员查看和编辑.PHPWord是一个用纯PHP编写的库,使用PHPWord可以轻松处理word文档内容,生成你想要的word文档. 下载源码 安装 ...
- numpy.random.randn()和numpy.random.rand()
1 numpy.random.rand() (1)numpy.random.rand(d0,d1,…,dn) rand函数根据给定维度生成[0,1)之间的数据,包含0,不包含1 dn表格每个维度 返回 ...