算法学习笔记(LCA)
L C A LCA LCA:树上两个点的最近公共祖先。(两个节点所有公共祖先中,深度最大的公共祖先)
L C A LCA LCA的性质:
- 在所有公共祖先中, L C A ( x , y ) LCA(x,y) LCA(x,y)到 x x x和 y y y的距离都最短。
- x x x, y y y之间最短的路径经过 L C A ( x , y ) LCA(x,y) LCA(x,y)。
- x x x, y y y本身也可以是它们自己的公共祖先。若 y y y是 x x x的祖先,则有 L C A ( x , y ) = y LCA(x,y) = y LCA(x,y)=y。
- L C A ( x , y , z ) = L C A ( x , L C A ( y , z ) ) LCA(x,y,z) = LCA(x, LCA(y,z)) LCA(x,y,z)=LCA(x,LCA(y,z))
- L C A ( x 1 , x 2 , . . . , x n ) = L C A ( d f s 序最大点, d f s 序最小点 ) LCA(x_1, x_2,...,x_n) = LCA(dfs序最大点,dfs序最小点) LCA(x1,x2,...,xn)=LCA(dfs序最大点,dfs序最小点)
本文主要介绍求 L C A LCA LCA的两种方法:倍增法和 T a r j a n Tarjan Tarjan。
先引入例题:
【模板】LCA
题目描述
给定一个 n n n个点以结点 1 1 1为根的树,有 q q q次询问,每次询问给出两个点 u , v u,v u,v,求 L C A ( u , v ) LCA(u,v) LCA(u,v)。
L C A ( u , v ) LCA(u,v) LCA(u,v)表示 u , v u,v u,v的最近公共祖先。
输入描述
第一行一个整数 n n n表示结点个数。 ( 1 ≤ n ≤ 2 × 1 0 5 ) (1 \leq n \leq 2 \times 10^5) (1≤n≤2×105)
第二行 n − 1 n−1 n−1个整数,表示 2 ∼ n 2∼n 2∼n结点的父亲。
第三行一个整数 q q q,表示询问次数。 ( 1 ≤ q ≤ 2 × 1 0 5 ) (1 \leq q \leq 2 \times 10^5) (1≤q≤2×105)
接下来 q q q行,每行两个整数 u , v u,v u,v。 ( 1 ≤ u , v ≤ n ) (1≤u,v≤n) (1≤u,v≤n)
输出描述
对于每次询问,一行一个整数表示结果。
输入样例1
5
1 1 2 3
3
1 2
2 4
1 5
输出样例1
1
2
1
倍增法:
大体就是让两个点不断向上走,直到走到最近的相同的点。如何快速地走?这里就需要用倍增法来实现。倍增法的原理利用了二进制的性质:任意一个数字都可以由一个或几个 2 2 2的幂相加得到,所以可以以 1 , 2 , 4 , 8... 1,2,4,8... 1,2,4,8...这种 2 2 2的幂作为一步的长度向上走。
因为我们不知道应该走多大,所以应该先尝试走大数,能走即走,再尝试走小步。
为了快速地进行跳跃,我们需要预处理出一个帮助我们进行跳跃的数组 f a [ N ] [ 20 ] fa[N][20] fa[N][20]( f a [ x ] [ i ] fa[x][i] fa[x][i]表示从 x x x出发向上走 2 i 2^{i} 2i步到达的位置)。计算 f a fa fa数组时用到了 d p dp dp的思路,这里有个递推公式: f a [ x ] [ i ] = f a [ f a [ x ] [ i − 1 ] ] [ i − 1 ] fa[x][i] = fa[fa[x][i - 1]][i - 1] fa[x][i]=fa[fa[x][i−1]][i−1],意思是从点 x x x出发,先跳 2 i − 1 2 ^ {i - 1} 2i−1步,再跳 2 i − 1 2 ^ {i - 1} 2i−1步。由小推到大。
得到这个数组之后,就可以快速地计算 L C A LCA LCA了。具体步骤如下:
先将点 x x x和点 y y y处理至同一深度。让深度较大的数以祖先链上深度与深度较小的那个点相等的点为目标进行跳跃。特殊的,如果该点就是深度较浅的那个点,则使用上述 L C A LCA LCA的性质中的第三条。
之后,点 x x x和点 y y y再同时向上跳跃。直至分别跳到 L C A ( x , y ) LCA(x,y) LCA(x,y)的两个儿子上。即 x ≠ y x \not = y x=y并且 f a [ x ] [ 0 ] = f a [ y ] [ 0 ] fa[x][0] = fa[y][0] fa[x][0]=fa[y][0]。
最后得到的 f a [ x ] [ 0 ] fa[x][0] fa[x][0]就是 L C A ( x , y ) LCA(x,y) LCA(x,y)。
时间复杂度为: O ( n l o g 2 n + q l o g 2 n ) O(nlog_2n + qlog_2n) O(nlog2n+qlog2n)
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9, T = 20;vector<int> g[N];
int fa[N][30], dep[N];void dfs(int x)
{dep[x] = dep[fa[x][0]] + 1; //预处理各个节点深度//预处理fa数组for(int i = 1; i <= T; ++i) fa[x][i] = fa[fa[x][i - 1]][i - 1];for(const auto &i : g[x]){dfs(i);}
}int lca(int u, int v)
{if(dep[u] < dep[v]) swap(u, v); //不妨设点u深度大于等于点v//跳跃,先走大步再走小步//将u点跳至于点v相同高度for(int i = T; i >= 0; --i){if(dep[fa[u][i]] >= dep[v]) u = fa[u][i];}if(u == v) return u;//一起往上跳for(int i = T; i >= 0; --i){if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];}return fa[u][0];
}int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int n; cin >> n;for(int i = 2; i <= n; ++i){cin >> fa[i][0];g[fa[i][0]].push_back(i);}dfs(1);int q; cin >> q;while(q--){int u, v; cin >> u >> v;cout << lca(u, v) << '\n';}return 0;
}
Tarjan
大概流程:
还是采用 d f s dfs dfs,访问到一个点的时候,先标记被访问,然后向下处理它的儿子节点,看儿子节点是否为所求 L C A LCA LCA有关的点,处理完儿子节点之后回溯上来时再处理自己,看自己是否为所求 L C A LCA LCA有关的点。再向上合并,合并采用并查集进行合并且使用路径压缩。
因为有多组询问,所以需要将询问离线。
对于一对点中的一个点处理的时候,若另一个点已经被访问过了,那么那个点在的并查集中的根节点就是它们的 L C A LCA LCA,这和 d f s dfs dfs的性质有关。都访问到的时候,它们一定在同一棵子树上,并且这颗子树的根显然就是它们的 L C A LCA LCA。
时间复杂度为: O ( n + q ) O(n + q) O(n+q)
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9;int pre[N], dep[N], ans[N], fa[N];
vector<int> g[N];
vector<pair<int, int>> Q[N];
bitset<N> vis;//并查集基础操作
int find(int x)
{return pre[x] = (pre[x] == x ? x : find(pre[x]));
}void merge(int x, int y) //将深度大的向深度小的合并,向上合并
{int fx = find(x), fy = find(y);if(dep[fx] < dep[fy]) swap(fx, fy);pre[fx] = fy;
}void dfs(int x)
{//顺手计算深度,合并时使用dep[x] = dep[fa[x]] + 1;vis[x] = true;for(const auto &y : g[x]) dfs(y); //先处理所有儿子for(const auto &[y, id] : Q[x]) //在处理自己{if(!vis[y]) continue; //如果对方未被访问就跳过ans[id] = find(y);}merge(x, fa[x]);
}void solve()
{int n; cin >> n;for(int i = 1; i <= n; ++i) pre[i] = i;for(int i = 2; i <= n; ++i){cin >> fa[i];g[fa[i]].push_back(i);}int q; cin >> q;//将询问离线for(int i = 1; i <= q; ++i){int x, y; cin >> x >> y;Q[x].push_back({y, i});Q[y].push_back({x, i});}dfs(1);for(int i = 1; i <= q; ++i) cout << ans[i] << '\n';
}int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int _ = 1;while(_--) solve();return 0;
}
L C A LCA LCA可以求树上两点之间的最短距离,也可以做树上差分,这里就不过多赘述。
相关文章:
算法学习笔记(LCA)
L C A LCA LCA:树上两个点的最近公共祖先。(两个节点所有公共祖先中,深度最大的公共祖先) L C A LCA LCA的性质: 在所有公共祖先中, L C A ( x , y ) LCA(x,y) LCA(x,y)到 x x x和 y y y的距离都最短。 x …...
记一次苹果appstore提审拒审问题1.2
有关苹果appstore审核1.2问题的处理方案 2023.8.6苹果回复 Bug Fix Submissions The issues weve identified below are eligible to be resolved on your next update. If this submission includes bug fixes and youd like to have it approved at this time, reply to thi…...
在做题中学习(59):除自身以为数组的乘积
238. 除自身以外数组的乘积 - 力扣(LeetCode) 解法:前缀积和后缀积 思路:answer中的每一个元素都是除自己以外所有元素的和。那就处理一个前缀积数组和后缀积数组。 而前缀积(f[i])是:[0,i-1]所有元素的乘积 后缀…...
centos 把nginx更新到最新版本
yum install epel-release # 添加 EPEL 软件仓库,这是 Nginx 官方软件仓库的依赖项 yum install yum-utils # yum-utils 包含了 yum-config-manager 工具,它可以让您轻松地启用、禁用或配置 yum 软件仓库 vi /etc/yum.repos.d/nginx.repo # 增加以下内容…...
01.认识HTML及常用标签
目录 URL(统一资源定位系统) HTML(超文本标记语言) 1)html标签 2)head标签 3)title标签 4)body标签 标签的分类 DTD文档声明 基础标签 1)H系列标签 2)…...
从零开始:C++ String类的模拟实现
文章目录 引言1.类的基本结构2.构造函数和析构函数3.基本成员函数总结 引言 在C编程中,字符串操作是非常常见且重要的任务。标准库中的std::string类提供了丰富且强大的功能,使得字符串处理变得相对简单。然而,对于学习C的开发者来说&#x…...
银河麒麟服务器操作系统V10-SP2部署gitlab服务
安装依赖 yum -y install python3-policycoreutils openssh-server openssh-clients postfix cronie curl下载gitlab-ce-15.4.2-ce.0.el8.x86_64.rpm安装包。 wget --content-disposition https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/8/gitlab-ce-15.4.2-ce.0…...
【计算机毕业设计】基于SSM+Vue的线上旅行信息管理系统【源码+lw+部署文档+讲解】
目录 1 绪论 1.1 研究背景 1.2 设计原则 1.3 论文组织结构 2 系统关键技术 2.1JSP技术 2.2 JAVA技术 2.3 B/S结构 2.4 MYSQL数据库 3 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 操作可行性 3.1.3 经济可行性 3.1.4 法律可行性 3.2系统功能分析 3.2.1管理员功能分析 3.2.…...
链表CPP简单示例
链表创建 链表打印全部内容 获取链表长度 链表根据指定位置添加元素 链表根据指定位置删除元素 #include <iostream> using namespace std;// 1、创建结构体// typedef 经常在结构中使用 typedef 别名 typedef struct node {int date;struct node* next; // 必须要自己…...
智能EDM邮件群发工具哪个好?
企业之间的竞争日益激烈,如何高效、精准地触达目标客户,成为每个市场战略家必须面对的挑战。在此背景下,云衔科技凭借其前沿的AI技术和深厚的行业洞察,匠心推出了全方位一站式智能EDM邮件营销服务平台,重新定义了邮件营…...
低代码与AI技术发展:开启数字化新时代
随着数字化转型的深入推进,低代码和AI技术逐渐成为各行各业关注的焦点。这两种技术的发展不仅改变了传统开发模式,还为企业创新和产业升级提供了新契机。本文将探讨这两种技术在实际应用中的相互促进作用,以及它们为我国经济社会发展带来的机…...
风电功率预测 | 基于遗传算法优化BP神经网络实现风电功率预测(附matlab完整源码)
风电功率预测 风电功率预测 | 基于遗传算法优化BP神经网络实现风电功率预测(附matlab完整源码)完整代码风电功率预测 | 基于遗传算法优化BP神经网络实现风电功率预测(附matlab完整源码) 基于遗传算法优化BP神经网络是一种常见的方法,用于改进BP神经网络在风电功率预测中的性…...
uni-segmented-control插件使用
dcloud插件市场 前端/uniapp 1.HBuildX打开目标项目 2.进入dcloud插件市场下载目标插件 3.看到如下提示(已经可以在目标项目中使用插件啦) 4.项目正式使用...
被动防护不如主动出击
自网络的诞生以来,攻击威胁事件不断涌现,网络攻防对抗已然成为信息时代背景下的一场无硝烟的战争。然而,传统的网络防御技术,如防火墙和入侵检测技术,往往局限于一种被动的敌暗我明的防御模式,面对攻击者无…...
ollama离线部署llama3(window系统)
首先介绍下ollama是什么?Ollama是一个开源的大型语言模型服务工具,旨在为用户提供本地化的运行环境,满足个性化的需求。具体来说,Ollama是一个功能强大的开源框架,可以简化在Docker容器中部署和管理大型语言模型&a…...
基于Django实现的(bert)深度学习文本相似度检测系统设计
基于Django实现的(bert)深度学习文本相似度检测系统设计 开发语言:Python 数据库:MySQL所用到的知识:Django框架工具:pycharm、Navicat、Maven 系统功能实现 登录页面 注册页面:用户账号,密码…...
数据中心网络随想-电路交换
数据中心网络扩容并不容易,涉及设备上架,切换等又硬又大的动作,期间对所有应用都会产生影响,所以理论上 “加钱加硬件” 这种看起来很简单的事实际上真不如 “写一个随时部署升级的端到端拥塞控制算法” 更容易实施。 傍晚绕小区…...
并行执行线程资源管理方式——《OceanBase 并行执行》系列 3
在某些特定场景下,由于需要等待线程资源,并行查询会遇到排队等待的情况。本篇博客将介绍如何管理并行执行线程资源,以解决这种问题。 《OceanBase并行执行》系列的内容分为七篇博客,本篇是其中的第三篇。 一并行执行概念二如何手…...
数据库系统概论(个人笔记)(第二部分)
数据库系统概论(个人笔记) 文章目录 数据库系统概论(个人笔记)2、关系模型简介2.1 关系数据库的结构2.2 数据库模式2.3 键2.4 模式图2.5 关系查询语言2.6 关系代数 2、关系模型简介 2.1 关系数据库的结构 Structure of Relational…...
WebView基础知识以及Androidx-WebKit的使用
文章目录 摘要WebView基础一、启动调整模式二、WebChromeClient三、WebViewClient四、WebSettings五、WebView和Native交互 Androidx-WebKit一、启动安全浏览服务二、设置代理三、安全的 WebView 和 Native 通信支持四、文件传递五、深色主题的支持六、JavaScript and WebAssem…...
【Ansible 入门实战】三种变量详解
Ansible 同名变量优先级实战详解这篇教程基于你当前的 Ansible 环境,通过 三种同名变量(主机变量 / 外部变量 / Play 变量) 的对比实验,完整展示变量优先级的验证过程。一、实验目标在同一个 Ansible Playbook 中,定义…...
Hi3861驱动MPU6050与OLED:嵌入式I2C传感器数据采集与显示实战
1. 项目概述与核心价值最近在捣鼓小熊派的Hi3861开发板,想用它来做个姿态传感器的小玩意儿。核心想法很简单:通过I2C总线读取MPU6050六轴传感器的数据,然后把姿态角(比如俯仰角、横滚角)实时显示在一块小小的OLED屏幕上…...
探索罗技鼠标宏:掌握PUBG压枪技术的完整路径
探索罗技鼠标宏:掌握PUBG压枪技术的完整路径 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 在《绝地求生》这款竞技性极强的射击游戏…...
从零打造专属显示器:面板、驱动板与外壳的实战选型指南
1. 为什么选择DIY显示器? 最近两年,显示器市场出现了不少高性价比的产品,但作为一个喜欢折腾的极客,我总觉得市面上的显示器少了点什么。要么是接口不够用,要么是外观太普通,要么就是某些参数达不到我的要求…...
Stateflow实战:构建LKA系统状态机的模块化建模与数据管理
1. 从零理解LKA系统与Stateflow建模 第一次接触车道保持辅助系统(LKA)时,我盯着那个能在高速上自动修正方向的方向盘看了半天。这玩意儿到底怎么判断什么时候该介入?后来才知道,核心就是藏在控制器里的状态机逻辑。Sta…...
告别VirtualBox的‘不是Host-Only适配器’错误:一个网络配置的深度修复指南
VirtualBox Host-Only网络故障全解析:从原理到实战修复 当你正准备启动VirtualBox中的开发环境虚拟机时,突然弹出的红色错误提示框让所有工作戛然而止——"Interface is not a Host-Only Adapter"。这个看似简单的网络适配器错误背后…...
3分钟让通达信自动画缠论中枢:告别复杂手动画线
3分钟让通达信自动画缠论中枢:告别复杂手动画线 【免费下载链接】ChanlunX 缠中说禅炒股缠论可视化插件 项目地址: https://gitcode.com/gh_mirrors/ch/ChanlunX 还在为缠论分析中的手动画线、笔段划分、中枢识别而烦恼吗?ChanlunX缠论插件为你带…...
CANN/HCOMM拓扑层级查询
HcclRankGraphGetLayers 【免费下载链接】hcomm HCOMM(Huawei Communication)是HCCL的通信基础库,提供通信域以及通信资源的管理能力。 项目地址: https://gitcode.com/cann/hcomm 产品支持情况 Ascend 950PR/Ascend 950DT࿱…...
5分钟快速上手:FlicFlac音频格式转换工具完全指南 [特殊字符]
5分钟快速上手:FlicFlac音频格式转换工具完全指南 🎵 【免费下载链接】FlicFlac Tiny portable audio converter for Windows (WAV FLAC MP3 OGG APE M4A AAC) 项目地址: https://gitcode.com/gh_mirrors/fl/FlicFlac 还在为不同设备间的音频格式…...
RK3568平台OpenCV交叉编译实战:从源码到部署的完整指南
1. 项目概述:为什么要在RK3568上折腾OpenCV?最近在做一个基于瑞芯微RK3568芯片的边缘计算盒子项目,其中一个核心需求就是要在设备上跑实时的图像识别算法。算法框架选型时,我们团队内部有过一些讨论,最终还是决定用Ope…...
