倍增法找lca——最近公共祖先

news2024/11/23 20:19:54

对于结点x和y,需要找他们的最近公共祖先

一个最简单的办法就是沿着x和y的父节点一个一个往上找

这样的时间复杂度是o(n),对于较大的数据量会TLE

今天要使用的方法是利用倍增来加速这个找lca的过程

倍增算法:

按2的倍数来往上找,也就是找第1,2,4,8,16,32...个父节点

而在这里,我们需要从大步往小步地去逐渐尝试

比如先尝试找第32个,不行再找第16个,以此类推

为什么不从小步往大步去尝试呢?

这和把一个十进制的数转为一个二进制的数是一样的,我们都是从最高位往最低位填1

如果填了这个1比要转换的数大了,那就不填

所以想要实现这样的算法,我们需要记录各个点的深度,以及他们2^i距离的祖先

const int N=1E5;
int n,m,s;
//链式前向星
int to[N<<1],nxt[N<<1],h[N],tot;
//dep[x]记录结点x的深度
//fa[x][j]记录结点x的距离为2^j的祖先
int dep[N],fa[N][20];
//lg[i]=log2[i]+1
int lg[N];
void init(){
    for(int i=1;i<=n;i++){
        lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    }
}
//x为访问的节点
//f为x的父亲
void dfs(int x,int f){
    //儿子的深度比父亲大1
    dep[x]=dep[f]+1;
    //节点x的距离为2^0的祖先就是自己的父亲f
    fa[x][0]=f;
    //更新距离x为2^i远的祖先
    //由于距离2^i不可能超过dep[x],所以i只要小于lg[dep[x]]就可以了
    for(int i=1;i<lg[dep[x]];i++){
        //关系转移的核心公式
        //距离x为2^i远的祖先就是——距离[距离x为2^(i-1)远的祖先]为2^(i-1)远的祖先
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    //开始遍历x的子节点
    for(int i=h[x],y;y=to[i];i=nxt[i]){ 
        //如果遍历到了自己的父亲,跳过
        if(y==f) continue;
        dfs(y,x);
    }
}

预处理完毕各个结点fa数组以后,我们就可以通过倍增算法来求得他们的lca了

在找lca的时候,可能有以下几种情况:

1.dep[x]==dep[y]

在这种情况下,我们只需要x和y同步往上爬,直到他们两个的祖先重合,就可以得到x与y的公共祖先了

2.dep[x]<dep[y]或dep[y]<dep[x]

这两种情况其实是等价的,只需要把x与y对调一下即可

现在不妨取dep[x]<dep[y]

那么这时会有两种情况:

(1) y是x的某个祖先

这个时候,x与y的lca一定是y

也就是说,只要返回y就可以了

(2)y不是x的某个祖先

这个时候,我们就应当先找到一个x的祖先,这个祖先和y的深度相同,然后再按照情况2处理

综上所述,实现代码如下:

int LCA(int x,int y){
    //第1种情况
    if(dep[x]<dep[y]){
        swap(x, y);
    }
    //当x与y不处于同一个深度的时候
    while(dep[x]>dep[y]){
        //找到距离x为dep[x]-dep[y]的祖先
        x = fa[x][lg[dep[x] - dep[y]] - 1];
    }
    //这个时候x和y同深度
    //如果y就是x的祖先的话
    //直接返回
    if(x==y){
        return y;
    }
    //如果不是的话
    //共同向上爬
    for (int k = lg[dep[x] - 1]; ~k;k--){
        //如果向上跳到的他们的祖先不相同,说明还没有合并到同一棵子树上
        //可以放心地跳到他们对应的祖先上
        if(fa[x][k]!=fa[y][k]){
            x = fa[x][k];
            y = fa[x][k];
        }
    }
    //循环结束以后,一定会有fa[x][0]==fa[y][0]
    //这个就是他们的lca
    return fa[x][0];
}

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

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

相关文章

Python 基础 (标准库):堆 heap

1. 官方文档 heapq --- 堆队列算法 — Python 3.12.4 文档 2. 相关概念 堆 heap 是一种具体的数据结构&#xff08;concrete data structures&#xff09;&#xff1b;优先级队列 priority queue 是一种抽象的数据结构&#xff08;abstract data structures&#xff09;&…

C#+uni-app医院HIS预约挂号系统源码 看病挂号快人一步

​​​​​​​ 提到去大型医院机构就诊时&#xff0c;许多人都感到恐惧。有些人一旦走进医院的门诊大厅&#xff0c;就感到迷茫&#xff0c;既无法理解导医台医生的建议&#xff0c;也找不到应该去哪个科室进行检查。实际上&#xff0c;就医也是一门学问&#xff0c;如何优化…

【STM32 RTC实时时钟如何配置!超详细的解析和超简单的配置,附上寄存器操作】

STM32 里面RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域&#xff0c;即在系统复位或从待机模式唤醒后&#xff0c;RTC的设置和时间维持不变。因为系统对后备寄存器和RTC相关寄存器有写保护&#xff0c;所以如果想要对后备寄存器和RTC进行访问&#xff0c;则需要通过操作…

我的3次软考高项通关之旅

1、缘起 初次听说软考是在2022年下半年了&#xff0c;软考的高级分为很多种&#xff0c;我起先想报考高级架构师&#xff0c;但是架构师一年才考一次&#xff0c;如果一次考不过得再准备一年&#xff0c;时间对我来说太长了&#xff0c;于是我决定报考一年考两次的高项。对于国…

10个AI高考上岸朋友圈文案设计

高考是人生中的一个重要时刻&#xff0c;上岸后分享朋友圈的文案可以既表达喜悦&#xff0c;也可以展现对未来的期待。以下是10个不同风格的高考上岸朋友圈文案&#xff0c;供你参考&#xff1a; 1. **梦想成真版**&#xff1a; "十年磨一剑&#xff0c;今朝试锋芒。高…

测试基础16:测试用例设计方法-测试大纲法

课程大纲 1、应用场景 验证页面跳转&#xff1a;有多个窗口/页面&#xff0c;每个窗口/页面有多个动作&#xff0c;每个动作之间有相互的联系的场景。看点击后&#xff0c;页面跳转正确与否。 2、设计步骤 step1.列出大纲&#xff1a;列出涉及的页面和页面可执行的动作。 s…

大厂面试官问我:Redis中热key和大key是怎么解决的?【后端八股文五:Redis热key和大key八股文合集】

往期内容&#xff1a; 大厂面试官问我&#xff1a;Redis处理点赞&#xff0c;如果瞬时涌入大量用户点赞&#xff08;千万级&#xff09;&#xff0c;应当如何进行处理&#xff1f;【后端八股文一&#xff1a;Redis点赞八股文合集】-CSDN博客 大厂面试官问我&#xff1a;布隆过滤…

2024HW面试真题(三)之看完蓝初变蓝高

以下是部分面试真题记录‍‍ 关于黑客&网络安全学习指南 学好 网络安全不论是就业还是做副业赚钱都不错&#xff0c;但要学会 网络安全 还是要有一个学习规划。最后给大家分享一份全套的 网络安全学习资料&#xff0c;给那些想学习网络安全的小伙伴们一点帮助&#xff01;…

eventbus和vuex

EventBus和Vuex EventBus 工作原理 创建一个vue实例&#xff0c;然后通过空的vue实例作为组件之间的桥梁&#xff0c;进行通信&#xff0c;利用到的设计模式有发布订阅模式 Vuex 工作原理 维护了一个state树&#xff0c;是独立的状态树&#xff0c;有明显的层级关系。不论…

振兴黄河新生力 打造文旅新地标——全国首家黄河会客厅在山东济南启幕

6月26日&#xff0c;由黄河文化发展工作站组织实施的全国首家黄河会客厅平台发布会暨山东基地启动仪式在济南成功召开。黄河会客厅以“民生黄河、生态动能、中华文明”为核心主题&#xff0c;融汇黄河智库、黄河文明、黄河产域、黄河金融、黄河科创、黄河物贸六大振兴赋能体系&…

Leetcode Hot100之矩阵

1. 矩阵置零 题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 解题思路 题目要求进行原地更改&#xff0c;也就是不能使用额外的空间&#xff0c;因此我们可以使用第一行的元素来记录对应的…

工业液晶屏G065VN01 V2规格书简介

G065VN01 V2 背面实物图 2. 概述 G065VN01 V2 专为 VGA &#xff08;640 x RGB x 480&#xff09; 分辨率和 16.2M&#xff08;RGB 6 位 FRC&#xff09;或 262k 色&#xff08;RGB 6 位&#xff09;的工业显示应用而设计。它由TFT-LCD面板、驱动IC、控制和电源电路板以及包括…

等保相关总结

等级划分准则 等保2.0基本框架 等保2.0变化解读 等级测评 3保1评 分保工作简介 分保工作流程 等保 等保工作流程&#xff1a;定级 -》备案 -》整改 -》测评 -》复核 关保 密评

C++系列-String(三)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” assign 这个接口的目的是用一个新的值代替之前的那个值 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> #include<list> #include&l…

Python自动造波器椭圆曲线波孤子解

&#x1f3af;要点 &#x1f3af;快速傅立叶变换算法周期域解椭圆曲线波 | &#x1f3af;算法数值解孤波脉冲和结果动画 | &#x1f3af;三种语言孤子解浅水表面波方程 | &#x1f3af;渐近分解算法孤子波 | &#x1f3af;自适应步长算法孤子波 | &#x1f3af;流体自动造波器…

react学习——17react中todoList案列

1、项目目录 2、App.js //创建“外壳”组件APP import React, {Component} from "react"; //引入Header组件 import Header from "./components/Header"; //引入List组件 import List from "./components/List"; //引入Footer组件 import Foot…

【unity笔记】八、Unity人物动画介绍

一、效果预览 本内容仅介绍为unity场景中的任务添加简单的动画效果。 二、小试牛刀 2.1 插件准备 在unity 中导入人物模型。常使用的免费人物模型和动画模型有Robot Kyle&#xff0c;Unity-Chan! Model&#xff0c;Basic Motions FREE。 其中Robot Kyle仅支持URP渲染。如…

docker内apt-get update Waiting for headers 0%

问题描述 docker运行debian等容器时&#xff0c;执行apt update或者apt-get update&#xff0c;可能会出现以下错误&#xff1a;root754a91d3630a:/# apt-get update 0% [Waiting for headers] [Waiting for headers] [Connected to developer.download.nvidia.com (152.199.3…

oracle11.2.0.4 RAC 保姆级静默安装(一) GI集群软件

一、响应文件准备 我们直接使用软件解压后的response文件夹中的响应文件模板进行修改 选择当前服务器的主机名,产品目录是在已存在的/u01/app目录基础上自动创建的无需提前创建oraInventory 按需选择语言,具体语言配置参考表格 一般rac默认选择安装类型为CRS_CONFIG 对应正…

Python 基础 (标准库):collections (集合类)

1. 官方文档 collections --- 容器数据类型 — Python 3.12.4 文档 Python 的 collections 模块提供了许多有用的数据类型&#xff08;包括 OrderedDict、Counter、defaultdict、deque 和 namedtuple&#xff09;用于扩展 Python 的标准数据类型。掌握 collections 中的数据类…