倍增求lca

LCA四种写法其一:倍增 文章目录众所周知一、倍增区间倍增二、LCA2.读入数据总结 众所周知 LCA有四种写法 一、倍增 fa[n][logn],fa[i][j]表示i节点的第2^j个父亲。 显然:fa[i][j]=fa[ fa[i][j-1] ][j-1] 即i的第2j个父亲是i的第2(j-1)个父亲的第2(j-1)个父亲。 于是,求i的第k个父亲的复杂度O(k)—>O(logk) 求i的第k个父亲: 1. for(int j=0; j<=log2(k); j++) 2. if((1<<j)&a. 阅读详情

倍增求lca 模板
求最近公共祖先lca(Least Common Ancestors),什么是公共祖先,给定一棵树,若节点z即使节点x的祖先,也是节点y的祖先,则称z是x,y的公共祖先,在x,y的所有公共祖先中,深度最大的节点称x,y的最近公共祖先,记做LCA(x,y)。
举个例子
在这里插入图片描述
LCA(4,5) = 2,LCA(5,6)=1,LCA(2,3)=1;
那么如何求LCA
先给出一张我们接下来要讲的例子:
例子
第一:暴力求法
先暴力dfs出每个点的深度,假设以 171717和 18 为例,既然要求LCA,那么我们就让他们一个一个向上跳,直到相遇为止。第一次相遇即是他们的LCA。 模拟一下就是:
17−>14−>10−>7−>3
18−>16−>12−>8−>5−>3
最终结果就是 3
但是这个算法的时间复杂度却是很高,所以我们采取了第二种重要的方法。
树上倍增法
设pre[x][k]表示x的2k 辈祖先,即从x向根节点走2k步到达的节点,若该节点不存在,则令pre[x][k] = 0,f[x][0]就是x的父节点。
所谓倍增,就是按2的倍数来增大,也就是跳 1,2,4,8,16,32 …… 不过在这我们不是按从小到大跳,而是从大向小跳,即按……32,16,8,4,2,1来跳,如果大的跳不过去,再把它调小。这是因为从小开始跳,可能会出现“悔棋”的现象。拿 5为例,从小向跳,5≠1+2+4,所以我们还要回溯一步,然后才能得出5=1+4;而从大向小跳,直接可以得出5=4+1。这也可以拿二进制为例,5(101),从高位向低位填很简单,如果填了这位之后比原数大了,那我就不填,这个过程是很好操作的。
还是以 17 和 18 为例(此例只演示倍增,并不是倍增LCA算法的真正路径):
17−>3
18−>5−>3
算法时间度为O(logn)。
接下来我们拆分算法步骤:
1:设depth[x]表示x的深度,不妨设depth[x]>=depth[y],否则交换x,y;
2:用上述二进制拆分思想,把x向上调整到与y同一高度。
3:若此时x==y,说明lca(x,y)就是x.
4:若此时x!=y,那么继续保持二进制拆分思想,把x,y同时向上调整,并保持深度一致并且二者不会相会。
/我们在跳的时候不能直接跳到它们的LCA,因为这可能会误判,比如4和8,在跳的时候,我们可能会认为1是它们的LCA,但1只是它们的祖先,它们的LCA其实是3。所以我们要跳到它们LCA的下面一层,比如4和8,我们就跳到4和5,然后输出它们的父节点,这样就不会误判了。/
5:此时x,y必定只差一步就会相会了,它们的父节点pre[x][0]就是我们要求的lca。

完整的求17和18的LCA的路径:
17−>10−>7−>3
18−>16−>8−>5−>3
解释:首先,18要跳到和17深度相同,然后18和17一起向上跳,一直跳到LCA的下一层(17是7,18是5),此时LCA就是它们的父亲

在算法实现的过程中,我们可以加上log2(x)log_2(x)log2​(x)的常数时间的优化。
下面给出各个步骤代码。
预处理:

void dfs(int f,int fa){
	depth[f] =  depth[fa] + 1;
	pre[f][0] = fa;
	for(int i=1;(1<<i) <= depth[f];i++)
		pre[f][i] = pre[pre[f][i-1]][i-1];//这个转移可以说是算法的核心之一
                                //意思是f的2^i祖先等于f的2^(i-1)祖先的2^(i-1)祖先
                                //2^i=2^(i-1)+2^(i-1)
	for(int i=head[f];i;i=nex[i]){
		if(ver[i] != fa)
		dfs(ver[i],f);
	}
}

查询x,y的lca:

int lca(int x,int y){
	if(depth[x] < depth[y]) swap(x,y); ////用数学语言来说就是:不妨设x的深度 >= y的深度
	while(depth[x] > depth[y])
	x = pre[x][lg[depth[x] - depth[y]]-1]; ////先跳到同一深度
	
	if(x==y) return x;//如果x是y的祖先,那他们的LCA肯定就是x了
	
	for(int i=lg[depth[x]]-1;i>=0;i--)  //不断向上跳(lg就是之前说的常数优化)
	if(pre[x][i]!=pre[y][i])  //因为我们要跳到它们LCA的下面一层,所以它们肯定不相等,如果不相等就跳过
	x = pre[x][i],y=pre[y][i];
	
	return pre[x][0]; 
}

给出测试链接:https://www.luogu.org/problem/P3379

给出模板:

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+7,M = 1e6+7;
int n,m,s,cnt;
int pre[N][22],depth[N],lg[N];
int head[M],ver[M],nex[M];
void add(int x,int y){
	ver[++cnt] = y;
	nex[cnt] = head[x];
	head[x] = cnt;
} 
void read(){
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1,x,y;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
}
void dfs(int f,int fa){
	depth[f] =  depth[fa] + 1;
	pre[f][0] = fa;
	for(int i=1;(1<<i) <= depth[f];i++)
		pre[f][i] = pre[pre[f][i-1]][i-1];//这个转移可以说是算法的核心之一
                                //意思是f的2^i祖先等于f的2^(i-1)祖先的2^(i-1)祖先
                                //2^i=2^(i-1)+2^(i-1)
	for(int i=head[f];i;i=nex[i]){
		if(ver[i] != fa)
		dfs(ver[i],f);
	}
}
int lca(int x,int y){
	if(depth[x] < depth[y]) swap(x,y); ////用数学语言来说就是:不妨设x的深度 >= y的深度
	while(depth[x] > depth[y])
	x = pre[x][lg[depth[x] - depth[y]]-1]; ////先跳到同一深度
	
	if(x==y) return x;//如果x是y的祖先,那他们的LCA肯定就是x了
	
	for(int i=lg[depth[x]]-1;i>=0;i--)  //不断向上跳(lg就是之前说的常数优化)
	if(pre[x][i]!=pre[y][i])  //因为我们要跳到它们LCA的下面一层,所以它们肯定不相等,如果不相等就跳过
	x = pre[x][i],y=pre[y][i];
	
	return pre[x][0]; 
}
void solve(){
	dfs(s,0);
	for(int i=1;i<=n;i++) ////预先算出log_2(i)+1的值,用的时候直接调用就可以了
	lg[i] = lg[i-1]+(1<<lg[i-1]==i);
	
	for(int i=1,x,y;i<=m;i++){
		scanf("%d%d",&x,&y);
		printf("%d\n",lca(x,y));
	}
}
int main(){
	read();
	solve();
	return 0;
}

资料参考:
https://www.luogu.org/blog/morslin/#
李煜东 算法竞赛进阶指南

倍增求LCA 求LCA的过程: 两个节点平层同时往上跳,直到相遇,相遇的点就是他们的LCA。但是很明显,如果这棵树的深度较大,那么就要跳很久了,所以可以采用倍增优化 设 F[x, k] 表示 x 的 第 2k 个祖先,即 x 节点向根节点走 2k 步到达的节点。f[x, 0] 就是 x 节点第一个祖先(也即父节点)。若该节点不存在(跳到了根节点外),我们则令 f[x, k] = 0 因为从x走2^k步, 可以分为先走2(k-1)步,再走2(k-1)步 得出F[x,k]的递推方程 ∀k∈[1,logn],F[x,k] 阅读详情

相关推荐

倍增算法入门 超详细解答+LCA+RMQ(ST表)+例题剖析

目录一、倍增算法二、倍增算法的应用:求LCA(最近公共祖先)附模板题三、倍增算法的应用:RMQ 问题(ST表)附模板题 一、倍增算法 要了解倍增之前,建议先看一下大佬的博客:【白话系列】倍增算法 看完以后相信你已经对倍增有了大致初步的了解,下面给出倍增的定义 (其实没什么用,好长一段话建议不看) 倍增 从字面的上意思看就是成倍的增长 ,这是指我们在进行递推时,如果状态空间很大,通常的线性递推无法满...

繁凡さん的博客 1万+

LCA问题(倍增法)

之前写过了LCA的两个在线算法之一:DFS+ST方法(DFS+ST)。本篇介绍另一种在线算法,用倍增思想来解决LCA问题。在学习倍增之前,先看一种倍增算法的退化版,有助于理解倍增法。 在找a和b的LCA时,先让a和b中深度较大的那一个,向上回溯到与另一个同样深度的位置上。例如下面这个图: 假设要找F和E的LCA,先让F向上回溯到他的父节点D的...

Q_M_X_D_D_的博客 1万+

SAP CO-PA获利分析避坑指南:从数据采集到报表设计的5个关键步骤

本文深入解析了SAP CO-PA获利分析模块从数据采集到报表设计的完整流程。文章重点剖析了数据源头、特征派生、获利段设计等关键步骤,并对比了基于账户与基于成本核算两种模式的差异,特别强调了在S/4HANA时代的选择与常见陷阱,旨在帮助企业构建可靠、可执行的盈利分析体系。

flink9streamer的博客 826

倍增LCA

朴素算法求LCA,即暴力求解,当树近乎为一条链时,找祖先时一级一级向上跳,时间复杂度接近O(n),所以可以考虑一次跳尽可能大的距离,即倍增算法;一次跳2^i(i=0,1,2....)级。 倍增法 一个节点的四级祖先就是这个节点的二级祖先的二级祖先; 设fa[j][i]为j节点的2^i级祖先;则fa[j][i]=fa[fa[j][i-1]][i-1]; 算法思想:求两节点的lca,先将深度深的结点用倍增法向上跳,直到两节点处于同一深度,此时有可能重合,则两点中任意一个结点即为lca;若没重合,则两节

qq_59144780的博客 4947

2026四款AI原生IDE实测:Trae、Qoder、CodeBuddy、Cursor能力边界深度解析

AI原生IDE正从代码编辑器演进为开发者智能工作流中枢,其核心在于对上下文理解、AST编辑意图建模与多模态任务调度的工程化实现。区别于传统插件式AI辅助,真正的AI原生IDE需具备知识库嵌入、符号图索引、操作链固化等底层能力,从而支撑Figma转码、N+1查询修复、跨语言迁移等复杂场景。Trae强调中文语境与企业规范的强绑定,Qoder聚焦AST级编辑轨迹预测,CodeBuddy通过IDE/插件/CLI三态划分控制权边界,Cursor则以云端Agent实现开发任务的时空并行。本文基于真实项目压测,揭示免费版

ctk87443的博客 2455

KiCad自动布线实战:FreeRouting插件安装与使用指南

在PCB设计流程中,布线环节往往占据大量重复性工作,尤其对于中小型双面板,成百上千条飞线的手动连接既繁琐又易出错。自动布线技术通过算法在给定设计规则和元件布局的基础上自动规划走线路径,能显著提升布线效率。FreeRouting作为一款开源自动布线器,与KiCad通过DSN/SES标准中间格式无缝配合,让工程师将精力集中于关键信号和布局优化,而将常规网络交给工具处理。本文从自动布线的原理与边界出发,讲解了FreeRouting的安装、DSN导出、参数设置、自动布线及结果回传的完整流程,并结合实际案例展示了在S

weixin_32025789的博客 277

倍增法在线求LCA(详解)

先贴上学习的文章: 洛谷P3379题解1 倍增讲解 在用Tarjan算法求LCA时会出现超时的现象,因为是一层一层的往上跳,于是就有了用倍增法求LCA,是层地往上跳。复杂度:O(nlogn) 1.倍增法思想: 按2的倍数跳,不过是从大到小跳,32,16,8,4,2,1。原因是从小到大跳会出现“悔棋”的现象: 从小到大:5!=1+2+4 从大到小:5=4+1 5<32 (不跳)...

m0_37579232的博客 1978

C++(Qt)软件调试---gdb调试入门用法(12)

学习GDB可以帮助程序员更好地调试程序,找到程序中的错误和问题,提高程序的质量和稳定性。 在开发大型软件时,程序中可能存在许多错误和问题,这些问题可能会导致程序崩溃或者出现不可预期的行为。 使用GDB可以帮助程序员更快地找到这些问题,并且提供一些调试工具来帮助程序员更好地理解程序的行为。

mahuifa的博客 5545

倍增求 LCA

LCA 指的是最近的公共祖先,倍增法求解 LCA 的步骤如下。 a. 求深度:对于每个节点 dfs 预处理处节点深度; b. 求倍增祖先:计算出每个节点向父元素跳 步所到达的节点(在这里 大于整棵树的最大深度) 备注: a. 设 f [ x , k ] 表示节点 x 向上跳 步能到达的祖先, f [ x , 0 ] 表示 x 的父元素,如对应节点不存在 f [ x , k ] = 0。 b. 将路径长度 分为两半,x 跳

Ryan_hsMax的博客 877

R语言Rstudio突然无法启动且报错:ERROR system error 42 [str: 一, len: 3, from: UTF-8, to: ISO8859-1]...如何解决

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 2846

20、基于图神经网络的脱氢焓预测方法研究

本文研究了基于图神经网络(GNN)的液态有机氢载体(LOHC)材料脱氢焓预测方法。通过分析现有GNN方法的局限性,提出了一种新的聚合自节点表示(AWS)方法,并结合丰富的原子特征和集成学习策略,显著提高了预测性能。实验结果表明,AWS在脱氢焓预测和多个基准化学性质预测任务中均优于现有GNN方法。此外,基于分子结构的集成方法进一步提升了模型的鲁棒性和准确性。研究展示了该方法在筛选LOHC材料中的潜力,并为未来预测更多化学性质奠定了基础。

pp12345的博客 103

倍增 || ST-RMQ 求LCA

视频讲解戳这里(bj聚聚讲的非常好,一听就懂) 由luogu一道模板题讲起传送门(都9102年,这题还卡输入输出,要吸氧才能过) LCA:求两个点的最近公共祖先 倍增求LCA: 有很多博客图文并茂讲的非常清楚,倍增LCA的主要思想就是,先将u,v(保证u的深度更深)两点调整到同一水平线 情况一:u==v,那就说明最近公共祖先是u,这种情况说明u,v在同一边,祖先自然是深度较浅的那一个...

一只不争气的蒸汽机的博客 345

uniapp [安卓苹果App端] - 实现APP开发后台保活+息屏后台持续运行效果,强制后台保活手机黑屏后进程存活后台保持网络连接或持续定位等功能提供支持(app后台运行休眠仍然可以确保一直运行)

uniapp APP开发后台保活,Uniapp-APP后台保活插件(安卓苹果ios后台保活)保证应用在后台继续运行,uniapp实现app保活 保后台运行 避免系统主动杀进程,如何让安卓APP一直在后台运行?uniapp 安卓 APP 后台持续运行(保活)iOS App后台保活,Android 后台运行白名单实现保活,保活息屏后台运行,uniapp后台保活,uniapp熄屏 后台运行,Android/ios进程保活/息屏后后台保持定位、网络运行,uniapp在android ios保活,挂后台可运行,安卓A

🏆 前端领域优质创作者 1万+

树上倍增法求 LCA

LCA(Lowest Common Ancestor,最近公共祖先)是树论中一个非常重要的概念,指的是在一棵树上两个节点最近的共同祖先节点。求解 LCA 的算法有很多,其中树上倍增法以其高效的查询效率(预处理 O (n log n),查询 O (log n))成为最常用的方法之一。本文将详细介绍树上倍增法的原理,并分享一份可直接复用的实现模板。

x3468714225的博客 595

手把手教你学 AI芯片 SOC软件开发专栏简介

在AI芯片(如NPU、GPU加速器)爆发式增长的今天,软件栈开发已成为AI应用落地的核心瓶颈。无论是模型推理加速、低延迟部署,还是能效优化,都依赖于对芯片底层软件的深度掌握。然而,许多开发者困于“只会调用API,不懂驱动实现”的困境,导致性能瓶颈难以突破。本专栏《手把手教你学 AI芯片 SOC软件开发》专为AI工程师、嵌入式开发者及系统架构师打造,从零基础切入,系统拆解AI芯片SOC(System on Chip)的完整软件栈,覆盖Runtime(运行时)

MHD0815的博客 168

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

倍增求LCA模板

#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=5e5+10,maxk=1e4+10,lenOfNode=52274,INF=0x3f3f3f3f; int lg[maxn],n,m,d[maxn],f[maxn][21],dep[maxn],cnt; int nxt...

tgyy_cool的博客 202

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

V4yneの求lca的倍增模板

代码: const int maxn=1e5+50; vector<int> edge[maxn]; int rot;int dep[maxn]; int rec[maxn][30]; void dfs(int x,int fa) { rec[x][0]=fa; dep[x]=dep[fa]+1; for(int i=0;i<edge[x].size();i++) { ...

V4yne.的博客 385

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

树:倍增求LCA(最近公共祖先)

嘿,LCA的题目可是我最喜欢的题目了,今天我就来讲讲如何求LCA? 对于如何LCA,我只会几种,不过比较实用。我重点去讲倍增求LCA。 倍增求LCA 倍增?什么是倍增? 字面上的意思便是成倍增长,其实也就是ST表(不懂的上网搜一搜 ) 言归正传,那我们该怎么用倍增求LCA呢? 首先,我们设 fi,jf_{i,j}fi,j​ 表示从 iii 这个点向上跳 2j2^j2j 步所到达的点。 然后我们可以一遍dfs,处理出所有的 fi,0f_{i,0}fi,0​ 即每个点的父亲。 接着我们考虑如何转移: 首先我们先

LeeCongWei的博客 304

祖孙询问(倍增法求LCA)(全网最详细)(带图解)

倍增法求LCA的核心思路和步骤通过图片和实例理解起来并不复杂,代码写起来更是很顺畅。如果仍有不理解的地方,欢迎留言或者私信。

2301_77160836的博客 1503

倍增法求LCA模版

用倍增法求LCA,板子好打,不容易错。 #include #include #include #include #include using namespace std; #define rep(i,a,n) for (int i=a;i<n;i++) #define per(i,a,n) for (int i=n-1;i>=a;i--) #define pb push_back #define

fouzhe的博客 784

树上倍增求LCA

#include #include #include #include #include #include #include #include #include #include #define MAXN 500007 using namespace std; int N; int M; int S; int cnt; int f[MAXN]; int lv[MAXN]; int anc[MA

Angel_wing_SKY的博客 1056

倍增法求Lca——求大佬指点

良心倍增法求lca大佬写的:https://blog.youkuaiyun.com/wjh2622075127/article/details/81060586 首先说Lca,中文最近公共祖先,见名思意很容易知道是求树上两个点最近的公共祖先 第一种方法:两个点同时向上走,并把经过的点标记,这样当有一个点走到被标记的点的时候,这个点就是要找的点。 第二种方法:很明显第一种方法是最朴素的,下面来说优于第一种...

wearegamer的博客 228
上一篇: 1496:【例 3】架设电话线
下一篇: 1553:【例 2】暗的连锁 树上差分
A_Pathfinder
博客等级 码龄8年 29粉丝 90原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值