两种lca的求法:树上倍增,tarjan
第一种:树上倍增
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的更多相关文章
- 倍增 Tarjan 求LCA
...
- FJUT 聪明的商人(树上倍增)题解
思路:求树上两点的距离,显然是dep[u] + dep[v] - 2 * dep[lca],用树上倍增去写. 参考:树上倍增的写法和应用(详细讲解,新手秒懂) 代码: #include<set& ...
- LCA离线Tarjan,树上倍增入门题
离线Tarjian,来个JVxie大佬博客最近公共祖先LCA(Tarjan算法)的思考和算法实现,还有zhouzhendong大佬的LCA算法解析-Tarjan&倍增&RMQ(其实你们 ...
- 图论分支-倍增Tarjan求LCA
LCA,最近公共祖先,这是树上最常用的算法之一,因为它可以求距离,也可以求路径等等 LCA有两种写法,一种是倍增思想,另一种是Tarjan求法,我们可以通过一道题来看一看, 题目描述 欢乐岛上有个非常 ...
- 树上倍增求LCA及例题
先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...
- Codevs 2370 小机房的树 LCA 树上倍增
题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...
- [学习笔记] 树上倍增求LCA
倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. ...
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...
- HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...
随机推荐
- 最全免费CDN公共库——网站提速
开源静态文件 CDN 我们的目标是提供这样一个仓库,让它尽可能全面收录优秀的开源库,并免费为之提供 CDN 加速服务,使之有更好的访问速度和稳定的环境.同时,我们也提供开源库源接入的入口,让所有人都可 ...
- OsWatcher 使用详解
软件下载地址: https://support.oracle.com/epmos/faces/DocumentDisplay?_afrLoop=520996062954556&id=30113 ...
- 第二节,surf特征检测关键点,实现图片拼接
初级的图像拼接为将两幅图像简单的粘贴在一起,仅仅是图像几何空间的转移和合成,与图像内容无关:高级图像拼接也叫做基于特征匹配的图像拼接,拼接时消去两幅图像相同的部分,实现拼接全景图. 实现步骤: 1.采 ...
- python进程.线程和协程的总结
I.进程: II.多线程threading总结 threading用于提供线程相关的操作,线程是应用系统中工作的最小单位(cpu调用的最小单位). Python当前版本的多线程没有实现优先级,线程组, ...
- 使用Boost Regex 的regex_search进行遍历搜索
在regex_search函数中,会将找到的第一个匹配结果保存到一个smatch类中. 然而如果搜索字符串中有多个匹配结果,则需要自己实现了. 在smatch中,有两个成员,官方文档如下: itera ...
- 设计模式C++学习笔记之九(Template Method模板方法模式)
模板模式也是相当简单的一种模式,而且是比较常用的.模板模式是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些 ...
- 解决python发送multipart/form-data请求上传文件的问题
服务器接收文件时,有时会使用表单接收的方式,这意味着我们需要使用Python的requests上传表单数据和文件. 常用的方式一般如下: data = { 'name': 'nginx' } file ...
- centos6下安装php7的memcached扩展
安装php7的memcached扩展 .编译安装libmemcached- wget https://launchpadlibrarian.net/165454254/libmemcached-1.0 ...
- 优秀员工的修炼——通往专家、管理之路
(一)好员工的素质 好员工的类型有很多种,尝试着抽象出一个定义吧--好员工是那些主管分配其任务放心.同事喜欢与其共事.对自己工作负责.志在自我提升和价值实现的人.知识经济时代,好员工首先是做好自我管理 ...
- class, extends和super es6语法
摘自https://www.cnblogs.com/queende7/p/8668497.html,谢谢博主的分享!