第一种:树上倍增

  f[x,k]表示x的2^k辈祖先,即x向根结点走2^k步达到的结点。

  初始条件:f[x][0]=fa[x]

  递推式:f[x][k]=f[ f[x][k-1] ][k-1]

一次bfs预处理f数组(nlogn),然后每次询问都可以在(logn)时间内求出x,y的lca

求lca的步骤

  1.令x的深度大于y,然后通过二进制拆分将x上调到与y同一个深度(依次用k=2^logn,...2^1,2^0试探)

  2.如果此时x==y,那么y=lca(x,y),算法结束

  3.继续用第一步的二进制拆分法同时将x,y往上提,保持深度一致,并且两者不可以相会

  4.最后f[x][0]=f[y][0]=lca(x,y)

注意第三步,x,y不可以相会!

int f[maxn][],d[maxn],t;
void bfs(){
queue<int>q;
q.push();d[]=;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i!=-;i=edge[i].nxt){
int v=edge[i].to;
if(d[v])continue;
f[v][]=u;
d[v]=d[u]+;
for(int k=;k<=;k++)
f[v][k]=f[f[v][k-]][k-];
q.push(v);
}
}
}
int lca(int x,int y){
if(d[x]<d[y])swap(x,y);
for(int i=;i>=;i--)
if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return y;
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][];
}

第二种,tarjan+并查集优化,离线算法

首先说明最简单的向上标记法:x,y沿着边不停往上寻找lca,直到相遇,相遇点就是lca

使用并查集对“向上标记法”进行优化

  在tarjan算法的dfs过程中,所有点分为三类

  1.没有被访问到的点。这类点被标记0

  2.正处于dfs阶段,即没有经过回溯的点,这类点给标记1

  3.已经结束dfs阶段,即已经回溯结束的点,这类点给标记2

每次一个点结束dfs阶段,就将其标记位2,并将这个点合并到其父亲所在的并查集中(可以保证其父亲此时的标记一定1),

当其他点有问题边连到该点时,这个问题的解就是其所在并查集的标号

比较形象化的理解,在dfs过程中,x,y结点的lca必定是其路径上深度最小的结点,而深度最小的结点在dfs访问到y时一定没有被回溯,并且此时x已经被回溯了,被归并在lca所在的集合中,

那么扫描和y有关的所有问题,如果另一个点已经被标记位2,说明y和这个点已经相遇过了,相遇的点就是这个点所在的并查集标号

那么就使用并查集来优化这个集合的合并即可。

//多次求树上两点之间的距离
vector<int>q[maxn],q_id[maxn];//查询链表
int v[maxn],f[maxn],ans[maxn];//标记数组,并查集
void tarjan(int x){
v[x]=;
for(int i=head[x];i!=-;i=edge[i].nxt){
int y=edge[i].to
if(v[y])continue;
d[y]=d[x]+edge[i].w;//求y的深度
tarjan(y);
f[y]=x;//回溯后将y并入x集合中
}
for(int i=;i<q[x].size();i++){
int y=q[x][i],id=q_id[x][i];
if(v[y]==){//y是已经回溯过的结点
int lca=find(y);//使用并查集求y的集合标记
ans[id]=min(ans[id],d[x]+d[y]-*d[lca]);
}
}
v[x]=;//x回溯完成了
}

两种lca的求法:树上倍增,tarjan的更多相关文章

  1. 倍增 Tarjan 求LCA

                                                                                                         ...

  2. FJUT 聪明的商人(树上倍增)题解

    思路:求树上两点的距离,显然是dep[u] + dep[v] - 2 * dep[lca],用树上倍增去写. 参考:树上倍增的写法和应用(详细讲解,新手秒懂) 代码: #include<set& ...

  3. LCA离线Tarjan,树上倍增入门题

    离线Tarjian,来个JVxie大佬博客最近公共祖先LCA(Tarjan算法)的思考和算法实现,还有zhouzhendong大佬的LCA算法解析-Tarjan&倍增&RMQ(其实你们 ...

  4. 图论分支-倍增Tarjan求LCA

    LCA,最近公共祖先,这是树上最常用的算法之一,因为它可以求距离,也可以求路径等等 LCA有两种写法,一种是倍增思想,另一种是Tarjan求法,我们可以通过一道题来看一看, 题目描述 欢乐岛上有个非常 ...

  5. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  6. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

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

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

  8. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  9. HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...

随机推荐

  1. Django REST framework 第五章 Relationships & Hyperlinked APIs

    到目前为止,API内部的关系是使用主键来代表的.在这篇教程中,我们将提高API的凝聚力和可发现性,通过在相互关系上使用超链接. Creating an endpoint for the root of ...

  2. ionic3安装

    1.安装 1)安装nodejs: 官网下载安装 2)可选安装 cnpm:  //安装了cnpm后,以后用到npm安装的东西都可以把npm替换成cnpm npm install -g cnpm --re ...

  3. 项目:《ssh框架综合项目开发视频》-视频目录和第六天的EasyUI简单讲解

    4 练习使用技术: Struts2 + hibernate5.x + spring4.x + mysql数据库 1 crm:customer relational manager,客户关系管理 2 c ...

  4. Exception:两个类具有相同的 XML 类型名称,请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称

    具体报错:  找到报错的类: 对XmlType重新命名(最简单粗暴的方法):

  5. Springboot的日志管理&Springboot整合Junit测试&Springboot中AOP的使用

    ==============Springboot的日志管理============= springboot无需引入日志的包,springboot默认已经依赖了slf4j.logback.log4j等日 ...

  6. 关于树的常见操作-C++面试

    #include <iostream> using namespace std; //树的存储结构与设计 struct BitNode { int data; BitNode* leftC ...

  7. ibevent 和 libev 提高网络应用性能【转】

    转自:https://www.cnblogs.com/kunhu/p/3632285.html 构建现代的服务器应用程序需要以某种方法同时接收数百.数千甚至数万个事件,无论它们是内部请求还是网络连接, ...

  8. HttpResonse 要记得关闭

    写了一个小程序,要识别网站上的图片,用到HttpRequest发请求,HttpResponse接受返回数据.刚开始循环可以跑两个,但是总是提示超时.后来查资料发现,在Http协议中,规定了同个Http ...

  9. ABP 框架从源码学习——abp框架启动和结束(1)

       1.abp框架的启动是从Global.asax文件的Application_Start启动的,当然代表Global的application必须从AbpWebApplication继承: publ ...

  10. EF使用Fluent API配置映射关系

    定义一个继承自EntityTypeConfiguration<>泛型类的类来定义domain中每个类的数据库配置,在这个自定义类的构造函数中使用我们上次提到的那些方法配置数据库的映射. 映 ...