第一种:树上倍增

  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. cookie——创建、获取、删除

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. pytroch 0.3 到 0.4版本迁移资料mark

    搜了一堆,还是官方资料给力,一份中文,一份英文,maek一下 https://www.pytorchtutorial.com/pytorch-0-4-0-migration-guide/ https: ...

  3. SpringSecurity实现短信验证码登录(Token)

  4. shell-自动按省市建立文件夹,并在每个城市下创建当前日期文件夹

    Code: #!/bin/bash date=`date +%Y%m%d` ProName="广东市" CityName="广州市 汕尾市 阳江市 揭阳市 茂名市 江门市 ...

  5. BIM 3D 数据交换格式 ----张建平(清华女)

    1.collada   EXPORTER 2.FBX    3D MAX 3.DAE 4.3D中的OBJ文件格式详解 (  http://www.cnblogs.com/slysky/p/408130 ...

  6. git与eclipse集成之代码冲突与解决

    1.1. 代码冲突与解决 目前使用git管理代码,产生冲突的原因,主要是当多个人向特性分支提交代码时,如果两个人修改了同一个文件,第二个人提交代码时就可能会冲突. 举例说明: 创建远程特性分支.远程个 ...

  7. $Django 发送邮件--django封装模块和python内置SMTP模块

    一 使用SMTP模块发送邮件 import smtplib from email.mime.text import MIMEText from email.header import Header m ...

  8. datepicker 属性设置 以及方法和事件

    DatePicker支持鼠标点选日期,同时还可以通过键盘控制选择: page up/down - 上一月.下一月 ctrl+page up/down - 上一年.下一年 ctrl+home - 当前月 ...

  9. PHP随机红包算法

    2017年1月14日 14:19:14 星期六 一, 整体设计 算法有很多种, 可以自行选择, 主要的"架构" 是这样的, 用redis decr()命令去限流, 用mysql去记 ...

  10. 转载:UML学习(三)-----序列图(silent)

    原文:http://www.cnblogs.com/silent2012/archive/2011/09/14/2172219.html UML的模型中可分为两种,动态模型和静态模型.用例图.类图和对 ...