LCA(Lowest Common Ancestor)
LCA(Lowest Common Ancestor)
定义
在树上取两点 x,yx,y,他们的 LCA 为距离他们最近的公共祖先。
本章主要讲的是倍增求 LCA。
暴力求取
- 从 xx 开始向上移动到根结点,并标记沿途结点。
- 从 yy 开始向上移动到根结点,第一个被标记的就是 xx 和 yy 的 LCA。
倍增求 LCA
从任意点对 (x,y)(x,y) 移到 xx 和 yy 的 LCA 的距离可拆分为 22 的幂的和。
若预处理任意点 xx 移动 22 的幂步所到达的结点编号,则不超过 \log_2{n}log2n 次即可找到 LCA。
具体实现
first:预处理倍增 DP
定义状态 dp_{i,j}dpi,j 表示点 ii 向上移动 2^j2j 步到达的结点编号。
状态转移方程:枚举 jj 从 11 到 \log_2 nlog2n,dp_{i,j}=dp_{dp_{i,j-1},j-1}dpi,j=dpdpi,j−1,j−1。
初始状态:dp_{i,0}=fa_idpi,0=fai。
代码片段
void pre_lca(int cur, int fa)
{dep[cur]=dep[fa]+1;dp[cur][0]=fa;for(int i=1;(1<<i)<=dep[cur];i++){dp[cur][i]=dp[dp[cur][i-1]][i-1];}for(int nxt:nbr[cur]){if(nxt!=fa)pre_lca(nxt,cur);}
}
second:处理单次询问
第一步:约定深度较大的点,若 dep_x>dep_ydepx>depy,交换 xx 和 yy。
第二步:将深度较大的结点 yy 倍增向上跳至深度等于 xx。
第三步:判断 xx 是否等于 yy。若已经相等则 xx 为 LCA,停止寻找。
第四步:xx 和 yy 一起倍增向上跳,只要 xx 和 yy 不重合。
第五步:xx 向上一步即为 LCA。
代码片段
int lca(int x, int y)
{if(dep[y]<dep[x])swap(x,y);for(int i=20;i>-1;i--){if(dep[dp[y][i]]>=dep[x]){y=dp[y][i];}}if(x==y)return x;for(int i=20;i>-1;i--){if(dp[x][i]!=dp[y][i]){x=dp[x][i],y=dp[y][i];}}return dp[x][0];
}
时间复杂度
预处理是 O(n \log_2 n)O(nlog2n) 的,中间单次求取仅为 O(n)O(n)
模板代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int dp[500005][21],dep[500005], n, m, s;
vector<int> nbr[500005];
void pre_lca(int cur, int fa)
{dep[cur]=dep[fa]+1;dp[cur][0]=fa;for(int i=1;(1<<i)<=dep[cur];i++){dp[cur][i]=dp[dp[cur][i-1]][i-1];}for(int nxt:nbr[cur]){if(nxt!=fa)pre_lca(nxt,cur);}
}
int lca(int x, int y)
{if(dep[y]<dep[x])swap(x,y);for(int i=20;i>-1;i--){if(dep[dp[y][i]]>=dep[x]){y=dp[y][i];}}if(x==y)return x;for(int i=20;i>-1;i--){if(dp[x][i]!=dp[y][i]){x=dp[x][i],y=dp[y][i];}}return dp[x][0];
}
signed main()
{ios::sync_with_stdio(0),cin.tie(0);cin>>n>>m>>s;for(int i=1;i<n;i++){int x, y;cin>>x>>y;nbr[x].push_back(y);nbr[y].push_back(x);}pre_lca(s,0);for(int i=1;i<=m;i++){int x, y;cin>>x>>y;cout<<lca(x,y)<<"\n";}
}
LCA 应用
- 求树上两点之间距离。
- 树上差分。
LCA 求树上两点之间距离
维护 dis_xdisx 表示根结点到 xx 的距离。
xx 到 yy 的简单路径的长度为 dis_x+dis_y-2\times dis_{\texttt{lca}(x,y)}disx+disy−2×dislca(x,y)。
LCA 例题
first:P5836
方法 1
点权可以转为 00 或 11,维护 dis_idisi 表示由根结点到 ii 的距离。
维护深度 dep_idepi,对于每次询问,若 (dis[a]+dis[b]-2*dis[lcad]+w[lcad]==dep[a]+dep[b]-2*dep[lcad]+1)&&c!='H'
或 dis[a]+dis[b]-2*dis[lcad]+w[lcad]==0&&c=='H'
则输出 00,否则输出 11。
方法 2
若一条边的两个端点的 ww 相同,则 unionn
这两个端点。
若一条路径上点权相同,则两个端点一定在同一集合。若该集合的权值不等于询问,输出 00,否则输出 11。
while(m--)
{int x, y;char c;cin>>x>>y>>c;if(c=='H'){cout<<!(find(x)==find(y)&&w[x]==0);}else{cout<<!(find(x)==find(y)&&w[x]==1);}
}
方法 3
维护 dp_{i,j}dpi,j 表示 ii 向上动 2^j2j 步到达的结点编号,维护 yes_{i,j,0/1}yesi,j,0/1 表示 ii 向上跳 2^j2j 步是否有 ww 为 0/10/1 的点。
yes[cur][i][0]=yes[cur][i-1][0]|yes[dp[cur][i-1]][i-1][0],yes[cur][i][1]=yes[cur][i-1][1]|yes[dp[cur][i-1]][i-1][1];
。
初始状态:dp_{i,0}=fa_idpi,0=fai,yes_{i,0,w_{fa}}=1yesi,0,wfa=1。
second:CF519E
若 AA 到 BB 的距离为奇数,则答案直接为 00。
否则分情况讨论:
-
中间位置的点 x=lcax=lca
xx 儿子结点中包含 AA 和 BB 的子树剔除,其余为答案。
-
中间位置的点 xx 不是 lcalca
约定深度较大的点为 BB,找到 BB 向上距离 xx 一步的点 pp,则答案为 size_x-size_psizex−sizep。
注意特殊情况:A==BA==B 时,答案为 nn。
从 lcalca 到 xx 的距离为 \frac{dep_B-dep_A}{2}2depB−depA。
void work(int x,int y)
{if(x==y){cout<<n<<"\n";return ;}if(dep[x]==dep[y]){for(int i=14;i>=0;i--){if(dp[x][i]!=dp[y][i]){x=dp[x][i],y=dp[y][i];}}cout<<size[1]-size[x]-size[y]<<"\n";return ;}if(dep[x]<dep[y]) swap(x,y);if((dep[x]-dep[y])%2==1){cout<<"0\n";return ;}int x2=x,len=(dep[x]-dep[y])/2;for(int i=14;i>=0;i--){if(dep[dp[x][i]]>=dep[y]){x=dp[x][i];}}if(x==y){len+=dep[x];for(int i=14;i>=0;i--){if(dep[dp[x2][i]]>len){x2=dp[x2][i];}}cout<<size[dp[x2][0]]-size[x2]<<"\n";return ;}for(int i=14;i>=0;i--){if(dp[x][i]!=dp[y][i]){x=dp[x][i],y=dp[y][i];}}len+=dep[x]-1;for(int i=14;i>=0;i--){if(dep[dp[x2][i]]>len){x2=dp[x2][i];}}cout<<size[dp[x2][0]]-size[x2]<<"\n";
}
Third:P8972 一切都已过去
见 题解:P8972 『GROI-R1』 一切都已过去 - 洛谷专栏
方便阅读搬过来。
从数据范围很容易发现,如果我们把边权累乘再判整数,炸掉是必然的,这时候,我们来发现一个性质:只有小数部分有 22 和 55 相乘的时候,才可能变成整数。当然,这并不是绝对的,例如 2.02 \times 52.02×5 就不是整数。从上面举的例子很容易发现一个性质:两个实数的乘积是否为整数与小数点数位也有关系。一对 22 和 55 可以抵消掉一个小数点数位(22 和 55 可以在任意且不同数位上,并且 22 和 55 的倍数也有用)。这时,我们可以将边权通过不断 \times 10×10 变成整数,并分解质因数分别求因数中 22 和 55 的个数(点权也要处理)。22 和 55 的个数求出来了,小数点数位也很好处理。最终的小数点位数应该是所有路径上的边权小数点位数之和,所以我们在将边权化整数时再维护一个变量统计小数点位数并记录到邻接矩阵里。若路径 xx 到 yy 的总边权乘上 xx 的点权得到的结果中 22 的个数和 55 的个数大于或等于总小数点位数,则其为整数。分别维护即可。
注意:若边权或点权为 00 则对应维护的当前点权或点权的 22 和 55 赋予极大值。
Latex有双倍问题,完整版请在安全访问中心 - 洛谷查看
相关文章:
LCA(Lowest Common Ancestor)
LCA(Lowest Common Ancestor) 定义 在树上取两点 x,yx,y,他们的 LCA 为距离他们最近的公共祖先。 本章主要讲的是倍增求 LCA。 暴力求取 从 xx 开始向上移动到根结点,并标记沿途结点。从 yy 开始向上移动到根结点,…...

张钹院士:大模型时代的企业AI发展趋势
在当今技术迅速发展的时代,生成式人工智能与大模型正成为推动产业变革的重要力量。随着AI技术的不断成熟与普及,它的应用已从个人领域扩展至企业层面,广泛覆盖各行各业。 那么,新技术究竟会给产业带来哪些积极地影响?…...

php连接sphinx的长连接事宜以及sphinx的排除查询以及关于sphinx里使用SetSelect进行复杂的条件过滤或复杂查询
一、php连接sphinx的长连接事宜以及sphinx的排除查询 在使用php连接sphinx时,默认的sphinx连接非长连接,于是在想php连接sphinx能否进行一些优化 publish:January 9, 2018 -Tuesday: 方法:public bool SphinxClient::open ( void ) — 建立到…...
抓包分析排查利器TCPdump
tcpdump命令介绍与常规用法。 基础命令介绍 # 固定语法 -i 指定网卡名称 -nn 显示IP地址 -w 指定输出的文件名称 tcpdump -i eth0 -nn -w test.cap-nn 不把主机的网络地址与协议转换成名字 -w 把数据包数据写入指定的文件 and 连接参数 host 指明主机 port 指明端口 src 源IP…...

八种排序算法的复杂度(C语言)
归并排序(递归与非递归实现,C语言)-CSDN博客 快速排序(三种方法,非递归快排,C语言)-CSDN博客 堆排序(C语言)-CSDN博客 选择排序(C语言)以及选择排序优化-CSDN博客 冒泡排序(C语言)-CSDN博客 直接插入排序(C语言)-CSDN博客 希尔排序( 缩小增量排序 )(C语言)-CSDN博客 计数…...

docker compose部署rabbitmq集群,并使用haproxy负载均衡
一、创建rabbitmq的data目录 mkdir data mkdir data/rabbit1 mkdir data/rabbit2 mkdir data/rabbit3 二、创建.erlang.cookie文件(集群cookie用) echo "secretcookie" > .erlang.cookie 三、创建haproxy.cfg配置文件 global log stdout fo…...

git强制推送代码教程
git强制推送代码教程 首先说明情况,我的代码remote了两个git库,现在想要推送到其中一个,但是版本不对,被拒绝,因此下面将进行强制推送 首先检查远程库都有哪些 git remote -v2. 检查当前的分支 git branch当前分支前…...
windows C++-高级并发和异步(三)
深入了解 winrt::resume_foreground(下) 调用 winrt::resume_foreground 时会始终先排队,然后展开堆栈。 也可选择设置恢复优先级。 winrt::fire_and_forget RunAsync(DispatcherQueue queue) {...co_await winrt::resume_foreground(queue, DispatcherQueuePrior…...

河北移动:核心系统数据库成功完成整体迁移 ,实现全栈国产|OceanBase案例
本文作者:移动通信集团河北有限公司架构规划专家,房瑞 项目背景: 中国移动通信集团河北有限公司一直在积极响应国家及集团的号召,以磐舟&磐基云原生为底座,结合国产浏览器、中间件、数据库、操作系统和服务器等&a…...
ZKRollup
目录 ZKRollup 基本概念 运作原理 特点与优势 应用场景 典型项目 ZKRollup ZKRollup,全称为Zero-Knowledge Rollup,是一种基于零知识证明的二层扩容方案(Layer 2)。它旨在通过提高交易处理效率和降低交易成本来扩展区块链网络的能力,尤其是在以太坊等区块链平台上得…...

letcode 分类练习 树的遍历
letcode 分类练习 树的遍历 树的构建递归遍历前序遍历中序遍历后序遍历 迭代遍历前序遍历中序遍历后序遍历 层序遍历层序遍历可以解决的问题107. 二叉树的层序遍历 II199. 二叉树的右视图637. 二叉树的层平均值429. N 叉树的层序遍历515.在每个树行中找最大值116.填充每个节点的…...

redisssion分布式锁
分布式锁的问题 基于setnx的分布式锁实现起来并不复杂,不过却存在一些问题。 锁误删问题 第一个问题就是锁误删问题,目前释放锁的操作是基于DEL,但是在极端情况下会出现问题。 例如,有线程1获取锁成功,并且执行完任…...

嘎嘎嘎拿到去年想要的包
一年多了 继续,把项目收尾吧 好好学前端,外企!react!从0开始,紧迫!加油!...

前奏编曲:如何编写二段式前奏
选好音源 Pianoteq 6 STAGE比较明亮些,适合做前奏的音源 确定和弦进行 比如4536251,每个小节2和弦,每个小节的和弦弹一下 优化和弦进行衔接和织体 二段式不用对和弦进行就近解决的处理,因为前奏前后要形成对比。 前半部分往…...
征服云端:Kubernetes如何让微服务与云原生技术如虎添翼
引言 在这个数字化转型的时代,微服务架构已经成为构建现代应用程序的首选方式。它不仅提高了开发效率,还增强了系统的可扩展性和灵活性。而随着云计算技术的迅猛发展,云原生的概念逐渐深入人心,它代表了一种全新的软件开发方法论…...

开源AI智能名片系统与高级机器学习技术的融合应用:重塑商务交流的未来
摘要:在数字化浪潮的推动下,人工智能(AI)技术,尤其是机器学习领域的快速发展,正深刻改变着各行各业的面貌。开源AI智能名片系统作为这一变革的先锋,通过集成并优化多种高级机器学习技术…...
Java中synchronized的偏向锁是如何减少锁开销的
偏向锁(Biased Locking)是一种优化 Java synchronized 锁的机制,旨在减少在无竞争情况下的锁开销。它通过将锁偏向于单个线程来优化锁的性能。以下是偏向锁减少锁开销的具体方式和原理: 偏向锁的工作原理 锁的初始状态: 当一个对…...
react18 + ts 使用video.js 直播.m3u8格式的视频流
一、安装依赖 我使用的video.js版本是8.17.3,从 Video.js 7.x 开始,HLS 支持被内置到了 Video.js 中所以不需要安装其他依赖 npm i video.js 二、创建VideoPlayer组件 import React, { useEffect, useRef } from react import videojs from video.js …...

使用 onBeforeRouteLeave 组合式函数提升应用的用户体验
title: 使用 onBeforeRouteLeave 组合式函数提升应用的用户体验 date: 2024/8/14 updated: 2024/8/14 author: cmdragon excerpt: 摘要:本文介绍了在Nuxtjs中使用onBeforeRouteLeave组合式函数来提升应用用户体验的方法。onBeforeRouteLeave允许在组件离开当前路…...

uni-app 吸顶方案总结
效果 页面级 uni.pageScrollTo 官方文档:https://uniapp.dcloud.net.cn/api/ui/scroll.html#pagescrollto 原生头部导航 uni.pageScrollTo({selector: #tabs,duration: 300 });(推荐)需要兼容自定义头部导航 <template><view id"demo1" :styl…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...