算法介绍:

看到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算法详解的更多相关文章

  1. [学习笔记] 树上倍增求LCA

    倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. ...

  2. [算法]树上倍增求LCA

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

  3. HDU6031 Innumerable Ancestors 倍增 - 题意详细概括 - 算法详解

    去博客园看该题解 题目 查看原题 - HDU6031 Innumerable Ancestors 题目描述 有一棵有n个节点的有根树,根节点为1,其深度为1,现在有m个询问,每次询问给出两个集合A和B ...

  4. kmp算法详解

    转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...

  5. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

  6. [转] KMP算法详解

    转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段.    我们这里说的K ...

  7. 【转】AC算法详解

    原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...

  8. KMP算法详解(转自中学生OI写的。。ORZ!)

    KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...

  9. EM算法详解

    EM算法详解 1 极大似然估计 假设有如图1的X所示的抽取的n个学生某门课程的成绩,又知学生的成绩符合高斯分布f(x|μ,σ2),求学生的成绩最符合哪种高斯分布,即μ和σ2最优值是什么? 图1 学生成 ...

随机推荐

  1. 项目测试完成后,总结典型性bug,以测试的角度,应该怎么筛选bug

    一个wap端改版项目完结了,总结下测试过程中的典型性bug:应该从哪个角度去总结? 有点疑问?不知道是以bug的影响度去总结,还是以优先级去总结(好像优先级和影响度是成正比的,优先级比较高的bug,影 ...

  2. office问题解决办法汇总

    1.Office2007或2010提示:您正试图运行的函数包含有宏或需要宏语言支持的内容 解决办法:word选项--加载项--管理com加载项--转到--把所有加载项删除 2.excel2010打开三 ...

  3. 链路聚合teaming(网卡绑定技术)2

    一.sentos7网卡绑定技术之teaming 这里介绍两种最常见的双网卡绑定模式: (1) roundrobin - 轮询模式 所有链路处于负载均衡状态,这种模式的特点增加了带宽,同时支持容错能力. ...

  4. 【Linux开发】OpenCV在ARM-linux上的移植过程遇到的问题4---共享库中嵌套库带路径【已解决】

    [Linux开发]OpenCV在ARM-linux上的移植过程遇到的问题4-共享库中嵌套库带路径[已解决] 标签:[Linux开发] 紧接着上一篇,我居然又尝试了一下编译opencv,主要是因为由于交 ...

  5. JDK8中接口的新特性

    在JDK8环境中,接口中的方法不再是只能有抽象方法,还可以有静态方法和default方法.实现类只需要实现它的抽象方法即可,JDK8中的接口有愈发向抽象类靠拢的感觉. 关于静态方法和默认方法作如下简述 ...

  6. 关于E980

    1. 浪商官网上面的内容貌似有点问题 来源: https://www.inspurpower.com/product/others.php?f=E980 但是wiki 里面的东西: 其实只有12cor ...

  7. 关于Java多线程的一些面试问题

    1.ArrayList和Vecoter区别? Array和ArrayList的异同点一.Array和ArrayList的区别#1. Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大 ...

  8. setTimeout、Promise、Async/Await 的执行顺序

    问题描述:以下这段代码的执行结果 async function async1() { console.log('async1 start'); await async2(); console.log( ...

  9. Mysql数据库在建表时指定engine等于InnoDB 或MyISAM的意义

    一.ISAM和InnoDB的定义 1. ISAM ISAM是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数据库被查询的次数要远大于更新的次数.因此,ISAM执行读取操作的速度很快 ...

  10. [七月挑选]IntelliJ IDEA常用设置

    title: IntelliJ IDEA常用设置 设置idea的类注释快捷键 File -> Settings -> Live Templates 1.右边的 + -> Templa ...