树上倍增求LCA详解

LCA(least common ancestors)最近公共祖先

指的就是对于一棵有根树,若结点z既是x的祖先,也是y的祖先(不要告诉我你不知道什么是祖先),那么z就是结点x和y的最近公共祖先。

定义到此。

那么怎么求LCA?

对于朴素思想,就是我要一步一步往上爬。。一步一步走。先把结点x和y整到同一深度,然后再一次一个深度的往上查,直到祖先一样才break(明显是个while)

但是,一步一步实在是太慢了,所以不能脚踏实地地走

那么,考虑跳着走,

跳着走的条件就是要满足一步步数尽可能多并且不跳过了。当然你跳过了在一步一步往下找也行啊QWQ

于是,在满足这两个条件的情况下,我们有了LCA算法:

一步条2的n次方。

对于每一步跳跃,我们要预处理一个二维数组f(father)f[x][i],表示对于当前的x结点,往上跳2^i个祖先,特别的,像数学中的,f[x][0]就是x的一代祖先。于是我们要用一个dfs预处理来解决这个f数组。后面我们会提到;

处理完f数组,那就很简单了。

输入x和y,表示要求结点x和结点y的LCA,那么我们开始求LCA:

对于x和y在不同高度,我们先把他们拉到一个高度,同样不能一步一步走,也要用到f数组。

这里我们要提前了解到一个定理:对于任意一个非零整数,我们都可以将他用2的次幂表示出来。也就是such as  : 11=2^3+2^1+2^0。这倒也不用证明,就像每个数都可以用二进制表示一样。

接着讲:在把x和y弄到同一高度时,我们要先做的是设x的深度dep要比y的深度dep要大,如果dep[y]>dep[x],那么把他们交换。原因是如果不交换,那么我们需要判断两种情况,用两个if以及几乎相同的代码。。(乱七八糟还占内存

然后用一个判断    if(dep[f[x][i]]>=dep[y])x=f[x][i];(此时x深度大于y),在这里用外层for循环来枚举i,但是i一定要从大到小!为什么?

安利一个故事(其实也不算):一个玻璃瓶,装了几块石头,满到瓶口。满了吗?没有。又装了一些沙子,满到瓶口。满了吗?没有。最后又装满了水,满到瓶口。终于满了。

那么,类比于x和y的深度的距离,这个瓶子的容积也是同样道理。从2的尽可能大的次幂去找,一旦能找到能接近他们的i,就更新dep[x],直到相等。类似于无限逼近,最后值相等的过程。如果i相等了,就说明他们的深度已经在同一层了。

与倍增到同一深度的过程相比,倍增找公共祖先也是类似的,但是有一点不同,就是你不知道什么时候找到他们的公共祖先,因此就没有查找的上限,那么就让他们尽可能接近。因此条件改成了这个:

if(f[x][i]!=f[y][i])
        {
            x=f[x][i];y=f[y][i];
        }

在执行完这个语句后,我们成功让x和y变成了某一节点z的左右儿子!

因为左右儿子是最接近但是又不相等的。

那么我们随便取其中一个找爸爸,就找到了LCA。

啊。。。。。。喘口气

AC代码:

有关链式存图不懂的的点这里。

 

#include<cstdio>
#include<iostream>
using namespace std;
int n,m,s,num=0,head[1000001],dep[1000001],f[1000001][23];
int a1,a2;
struct edg{int next,to;
}edge[1000001];
void edge_add(int u,int v)//链式前向星存图 
{num++;edge[num].next=head[u];edge[num].to=v;head[u]=num;edge[++num].next=head[v];edge[num].to=u;head[v]=num;
}
void dfs(int u,int father)//对应深搜预处理f数组 
{dep[u]=dep[father]+1;for(int i=1;(1<<i)<=dep[u];i++){f[u][i]=f[f[u][i-1]][i-1];}for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(v==father)continue;//双向图需要判断是不是父亲节点 f[v][0]=u;dfs(v,u);}
}
int lca(int x,int y)
{if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层 
    {if(dep[f[x][i]]>=dep[y])x=f[x][i];if(x==y)return x;}for(int i=20;i>=0;i--)//从大到小枚举 
    {if(f[x][i]!=f[y][i])//尽可能接近 
        {x=f[x][i];y=f[y][i];} } return f[x][0];//随便找一个**输出 
}
int main(){scanf("%d%d%d",&n,&m,&s);for(int i=1;i<n;i++){scanf("%d",&a1);scanf("%d",&a2);edge_add(a1,a2);//链式存边 
    }dfs(s,0);for(int i=1;i<=m;i++){scanf("%d %d",&a1,&a2);printf("%d\n",lca(a1,a2));//求两个节点的LCA 
    }
} 

 

完结。。

 

转载于:https://www.cnblogs.com/lbssxz/p/11114819.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/424327.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[导入]画带阴影效果的文字

画带阴影效果的文字文章来源:http://blog.csdn.net/net_lover/archive/2004/07/06/35553.aspx 转载于:https://www.cnblogs.com/zhaoxiaoyang2/archive/2004/07/07/816094.html

174. Dungeon Game

文章目录1题目理解2 分析1题目理解 故事背景&#xff1a;恶魔把公主抓走了&#xff0c;关在地牢里面。骑士想要把公主救出来。初始化的时候&#xff0c;骑士有一个健康值init。 输入&#xff1a;int[][] dungeon表示地牢中魔鬼布局图。dungeon[i][j]>0&#xff0c;恶魔会提…

第八十期:初创公司5大Java服务困局,阿里工程师如何打破?

初创公司遇到的每一个问题都可能攸关生死。创业之初更应该总结行业的常见问题&#xff0c;对比方案寻找最优解。 作者&#xff1a;常意 初创公司遇到的每一个问题都可能攸关生死。创业之初更应该总结行业的常见问题&#xff0c;对比方案寻找最优解。阿里巴巴地图技术专家常意在…

关于某些人和某些事的断想

关于某些人和某些事的断想<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />人的一生总会碰到这样那样的一些人和一些事&#xff0c;偶然或必然。这些人、这些事或许在我们的心里荡起过些许的波澜&#xff1b;又或许只是一闪而过&…

第八十一期:Java性能优化:35个小细节,提升你的Java代码运行效率

如果项目着眼于尽快无BUG上线&#xff0c;那么此时可以抓大放小&#xff0c;代码的细节可以不精打细磨&#xff1b;但是如果有足够的时间开发、维护代码&#xff0c;这时候就必须考虑每个可以优化的细节了&#xff0c;一个一个细小的优化点累积起来&#xff0c;对于代码的运行效…

Python数据类型与运算符号

一&#xff1a;数据类型 【1】为什么要有数据类型 &#xff08;1&#xff09;不同的数据含有不同的特征 例如&#xff1a;有文本数据 音频数据 视频数据 &#xff08;2&#xff09;不同的特征需要有不同的类型用来描述 二&#xff1a;数据类型的分类 【1】 &#xff08;1&#…

85. Maximal Rectangle

用dp计算矩形面积 文章目录1题目理解2分析2.1 暴力搜索2.2 动态规划3 相关题目1题目理解 输入&#xff1a;char[][] matrix 是一个二维数组&#xff0c;值由0和1组成。 输出&#xff1a;一个矩形的面积&#xff0c;这个矩形只包含1。 例子&#xff1a; Input: [ [“1”,“0”,…

全面搞定jive3.1.1

全面搞定jive3.1.1yippit 原创 (参与分&#xff1a;351&#xff0c;专家分&#xff1a;1740) 发表&#xff1a;2003-9-13 下午8:33 版本&#xff1a;1.0 阅读&#xff1a;8316次 近日坛子里面很多人问起这个问题&#xff0c;要么中文显示乱码出错&#xff0c;要么不能数…

spring mvc学习(6):springMVC的常见注解

1RequestMapping的位置可以在类名或者方法名之前 或者同时加在两个位置 最终的路径是两个位置路径的组合 value是默认的名称&#xff0c;可以省略&#xff0c;如果有其他参数&#xff0c;就不能省略 如下配置的访问路径&#xff1a;协议://主机&#xff1a;//端口/虚拟路径…

powershell some check

// TODO 待处理 1 # powershell 编写的某些校验2 3 function listChecks() {4 write-host 可用的校验;5 write-host CRC - 循环冗余校验;6 return -- done;7 }8 9 # 字节数组 CRC, 不知道是不是符合CRC定义 10 function crcCheck($byteArray) { 11 if ($byteAr…

801. Minimum Swaps To Make Sequences Increasing

文章目录1题目理解2 暴力搜索3 动态规划3.1第一种情况3.2第二种情况1题目理解 输入&#xff1a;两个int数组A和B&#xff0c;长度都不为0&#xff0c;并且长度相同。 输出&#xff1a;最小交换次数。 规则&#xff1a;最终想要得到两个严格递增的数组。如果原始数组不符合要求…

用属性还是字段?

用属性还是字段&#xff1f; 我觉得对于实体类(没有方法的类)&#xff0c;只要用字段就好了&#xff0c;没必弄得像下面这个样子&#xff1a; private AttributeConfig m_ColumnMap;public AttributeConfig ColumnMap{get{return m_ColumnMap;}set{m_ColumnMapvalue;}}posted …

spring mvc学习(7):springmvc学习笔记(常用注解)

1. Controller Controller注解用于表示一个类的实例是页面控制器(后面都将称为控制器). 使用Controller注解定义的控制器有如下特点: 不需要继承任何类, 也不需要实现任何接口可以处理多个请求可以使用Servlet的相关特性 spring自动扫描所有基于注解的类, 并将其注册为spring…

模板——树状数组求逆序对

题目链接&#xff1a;https://www.luogu.org/problemnew/show/P1908 1 #include <map>2 #include <set>3 #include <cmath>4 #include <queue>5 #include <string>6 #include <cstdio>7 #include <cstring>8 #include <iostream&…

818. Race Car

文章目录1 题目理解2 BFS3 dp3.1 基本情况3.2 递归方程分析3.2.1 先超过target再调头3.2.2 不超过target4 说明1 题目理解 先讲规则。一辆小汽车停在位置0&#xff0c;并且方向朝向右侧&#xff0c;并且速度为1。小汽车每次可以选择加速A&#xff0c;那加速一次&#xff0c;新…

spring mvc学习(8):springmvc常用注解代码

目录结构 web.xml <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xmlns"http://java.sun.com/xml/ns/javaee" xsi:schemaLocation"http://java.sun.com/xml…

找了好久的BUG

找了好久的BUG <rsp:WEBPAGE id"PageContainer" TabSectionID"*****" runat"server"></rsp:WEBPAGE> <rsp:PLACEHOLDER id"AdminPage_Title" runat"server">公文流转流程工作点定义</rsp:PLACEHOLDER&…

python-if条件判断与while/for循环

条件判断if 让计算机像人一样&#xff0c;能判断是非对错&#xff0c;根据条件做一些事情。 if ------ if代码结构&#xff1a;------- if 条件:代码体tips&#xff1a;同一缩进范围内的代码被视作同一代码体,python官方推荐python缩进一次为4个空格is_happy True if is_happ…

第八十二期:掌握这些监控报警优化技巧,百万年薪不在话下!

运维工程师面试者第一个问题是&#xff1a;需要值班吗?笔者自己也曾经历过月入十万的时期&#xff0c;在那个时候&#xff0c;数个系统同时发布下一代版本&#xff0c;而老系统还需要过渡很长时间&#xff0c;工作量直接翻倍。 作者&#xff1a;焦振清 运维工程师面试者第一…

dp按照规模分类总结

本文章的内容来源于花花酱dp2。 做多了dp的题目之后总觉得有什么规律&#xff0c;但是自己没总结出来。花花酱按照输入规模、子问题个数、在解决一个问题的时候需要依赖的子问题个数为特征对题目做了分类。 其中绿色是比较简单的 &#xff0c;黄色是中等的&#xff0c;粉色是…