洛谷 P3379:最近公共祖先(LCA)← RMQ+欧拉序

【题目来源】
https://www.luogu.com.cn/problem/P3379

【题目描述】
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

【输入格式】
第一行包含三个正整数 N,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来 N−1 行每行包含两个正整数 x,y,表示 x 结点和 y 结点之间有一条直接连接的边(数据保证可以构成树)。
接下来 M 行每行包含两个正整数 a,b,表示询问 a 结点和 b 结点的最近公共祖先。

【输出格式】
输出包含 M 行,每行包含一个正整数,依次为每一个询问的结果。

【输入样例】
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

【输出样例】
4
4
1
4
4

【说明/提示】
对于 30% 的数据,N≤10,M≤10。
对于 70% 的数据,N≤10000,M≤10000。
对于 100% 的数据,1≤N,M≤
500000,1≤x,y,a,b≤N,不保证 a≠b。

【算法分析】
● 一般来讲,求 LCA 有 3 种常见方法:倍增、
RMQ+欧拉序、tarjan(离线)。本题代码介绍“RMQ+欧拉序”法求LCA。

● 欧拉序:
https://blog.csdn.net/hnjzsyjyj/article/details/139681246
欧拉序有常见的两种情况。下图是适用于求 LCA 的第一种情况的欧拉序。由图可知,此图的第一种情况的欧拉序为:1,2,3,4,3,5,3,6,3,2,7,2,1,8,9,8,1

第一种情况的欧拉序具有如下性质:即若设 first[u] 是欧拉序中某结点 u 第一次出现的位置,first[v] 是欧拉序中某结点 v 第一次出现的位置,树上两结点 u, v 的最近公共祖先(LCA),为欧拉序区间 [first[u], first[v]][first[v], first[u]] 中时间戳最小的结点。其中,某结点的时间戳可以理解为第一次 DFS 遍历到该结点的顺序。 据此性质,易知利用欧拉序求 LCA,本质上就是一个 RMQ 问题。而 RMQ 问题常用 ST 算法来初始化数据

● ST 算法:
https://blog.csdn.net/hnjzsyjyj/article/details/103429761
ST算法(Sparse Table,稀疏表)主要用于解决区间最值问题(即RMQ问题)。因为ST算法求解RMQ问题时的时间复杂度只有O(nlogn),查询时间复杂度为常数阶O(1),所以我们还常称ST算法为TLE的死敌。虽然还可以使用线段树、树状数组、splay等算法求解区间最值问题,但是ST算法比它们更快,更适用于在线查询
ST算法分成两部分:离线预处理O(nlogn)和在线查询O(1)。
(1)离线预处理:运用DP思想求解区间最值,并将结果保存到一个二维数组中。
(2)在线查询:对给定区间进行分割,并借助上步中的二维数组求最值。
本题利用了
ST算法求解RMQ问题,ST算法分预处理及询问两部分。要理解ST算法,首先要注意下文表述中的移位运算符 >>及<< 的优先级比四则运算 +-*/ 的优先级高。这样就能理解 1<<(j-1) 及 1<<j-1 代表不同的运算,即 1<<(j-1) 等价于 2^(j-1)1<<j-1  等价于 2^j-1
(1)预处理
ST算法首先约定用 a[1] ~ a[n] 表示给定的一组数,
f[i][j]表示从 a[i] ~ a[i+1<<j-1] 范围内的最大值,也即以 a[i] 为起点的连续 2^j 个数的最大值(∵ a[x] ~ a[y] 包含有 y-x+1 个数)。由于ST算法用到了倍增思想,因此自然有将 2^j 个数从中间平均分成两等分的实践,显然每一部分有 1<<(j-1) 个数,即2^(j-1) 个数。显然,初始范围 a[i] ~ a[i+1<<j-1] 被等分后,第一部分范围为 a[i] ~a[i+1<<(j-1)-1],第二部分范围为 a[i+1<<(j-1)] ~ a[i+1<<j-1],分别对应于 f[i][j-1] 和 f[i+1<<(j-1)][j-1]
综上,得
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1])

(2)查询
若给定查询区间 [x,y],若利用ST算法求此区间内的最大值。则需先求出最大的 k,使之满足
2^k ≤ y-x+1
在此基础上,区间
[x,y]=[x,x+2^k-1]∪[y-2^k+1,y],则区间 [x,y] 内的最大值为 max(f[x][k],f[y-(1<<k)+1][k])

据上,利用ST算法查询区间 [x,y] 的最大值,计算式如下:
k=log2(y-x+1)
max(f[x][k],f[y-(1<<k)+1][k])


● 快读:https://blog.csdn.net/hnjzsyjyj/article/details/120131534

int read() { //fast readint x=0,f=1;char c=getchar();while(c<'0' || c>'9') { //!isdigit(c)if(c=='-') f=-1;c=getchar();}while(c>='0' && c<='9') { //isdigit(c)x=x*10+c-'0';c=getchar();}return x*f;
}

● 链式前向星:https://blog.csdn.net/hnjzsyjyj/article/details/139369904
val[idx]:存储编号为 idx 的边的值
e[idx]:存储编号为 idx 的结点的值
ne[idx]:存储编号为 idx 的结点指向的结点的编号
h[a]:存储头结点 a 指向的结点的编号

【算法代码】

#include<bits/stdc++.h>
using namespace std;const int maxn=5e5+5;
const int maxm=maxn<<1;
int f[maxn<<1][20]; //log2(5e5)<20;
int id[maxn<<1][20];
int h[maxn],e[maxm],ne[maxm],idx;
bool st[maxn];
int ola[maxn],a[maxn<<1],dep[maxn];
int n,m,root;
int tot;inline int read() { //fast readint x=0,f=1;char c=getchar();while(c<'0' || c>'9') { //!isdigit(c)if(c=='-') f=-1;c=getchar();}while(c>='0' && c<='9') { //isdigit(c)x=x*10+c-'0';c=getchar();}return x*f;
}inline void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}inline void ola_seq1(int u,int fa) {a[++tot]=u;ola[u]=tot;dep[u]=dep[fa]+1;st[u]=true;for(int i=h[u]; ~i; i=ne[i]) {int j=e[i];if(j==fa) continue;if(!st[j]) ola_seq1(j,u);a[++tot]=u;}
}int main() {memset(h,-1,sizeof(h));n=read(),m=read(),root=read();for(int i=1; i<n; i++) {int x=read(),y=read();add(x,y);add(y,x);}ola_seq1(root,0);for(int i=1; i<=tot; i++) {f[i][0]=dep[a[i]];id[i][0]=a[i];}for(int j=1; j<=20; j++)for(int i=1; i<=tot-(1<<j)+1; i++) {if(f[i][j-1]>f[i+(1<<(j-1))][j-1]) {f[i][j]=f[i+(1<<(j-1))][j-1];id[i][j]=id[i+(1<<(j-1))][j-1];} else {f[i][j]=f[i][j-1];id[i][j]=id[i][j-1];}}for(int i=1; i<=m; i++) {int le=read(),ri=read();le=ola[le],ri=ola[ri];if(ri<le) swap(le,ri);int k=log2(ri-le+1); //emphasis     if(f[le][k]<f[ri-(1<<k)+1][k]) printf("%d\n",id[le][k]);else printf("%d\n",id[ri-(1<<k)+1][k]);}return 0;
}/*
in:
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5out:
4
4
1
4
4
*/




【参考文献】
https://www.jianshu.com/p/050b589d039e
https://blog.csdn.net/dingqiongliang0363/article/details/102168530
https://www.cnblogs.com/lyttt/p/17355807.html
https://blog.csdn.net/weixin_44035017/article/details/99480717
https://blog.csdn.net/weixin_45963335/article/details/107912901
https://www.cnblogs.com/mpeter/articles/11324817.html
https://blog.csdn.net/diaoqi6581/article/details/101999564
https://blog.csdn.net/m0_37809890/article/details/82856158

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

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

相关文章

PostgreSQL源码分析——INSERT

这里我们对INSERT语句进行分析&#xff0c; 只分析其宏观过程&#xff0c;具体细节后续再分析。我们就分析下面的语句的执行过程。 insert into t1 values(4,4);主流程 主流程如下&#xff1a; exec_simple_query --> pg_parse_query //语法解析--> raw_parser-->…

数据库面试题-ElasticSearch

数据库面试题-ElasticSearch 1、ElasticSearch是什么?2、谈谈ElasticSearch分词与倒排索引的原理?3、说说ElasticSearch分段存储的思想?4、说说你对ElasticSearch段合并的策略思想的认识?5、知道什么是文本相似度TF-IDF吗?6、说说ElasticSearch写索引的逻辑?7、说说Elast…

AI大模型的战场:通用大模型VS垂直大模型,谁会赢?

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

Clickhouse备份恢复_clickhouse-backup方式备份恢复的使用介绍

https://clickhouse.com/docs/zh/operations/backup https://github.com/Altinity/clickhouse-backup?tabreadme-ov-file#readmeclichouse-backup备份的总结 1、clichouse-backup备份的方式是物理备份 2、clichouse-backup只能在数据库本机运行备份&#xff0c;在远程异机去备…

联合类型和交叉类型

联合类型和交叉类型 在TypeScript中,除了基本的类型(如 number、string、boolean 等),我们还可以使用更加高级的类型来描述复杂的数据结构。其中,联合类型和交叉类型就是两个非常有用的高级类型。 联合类型(Union Types) 联合类型允许一个变量可以是多种类型中的任意一种。我…

Mybatis (plus 也适用)原生直接执行某句SQL

场景 想要不论传入什么sql 都能直接执行 示例 Autowiredprivate SqlSessionTemplate sqlSessionTemplate;public void executeSql(String replaceSql) {if (StringUtils.isEmpty(replaceSql)) {return;}try {SqlSession sqlSession sqlSessionTemplate.getSqlSessionFactory…

二、利用YOLOv8解决现实世界的问题

Ultralytics Solutions提供顶尖的YOLO模型应用&#xff0c;提供现实世界的解决方案如&#xff1a;目标记数&#xff0c;模糊和安全系统&#xff0c;提升效率和准确率在各种工业中。探索YOLOv8在实用性和有效性上的强大功能。 解决方案&#xff1a; 下面展示利用Ultralytics So…

abstract 的 method 是否可同时是 static,是否可同时是 native,是否可同时是 synchronized?

在 Java 中&#xff0c;abstract 方法不能同时是 static、native 或 synchronized。让我们详细解释每种情况&#xff0c;并提供相应的代码示例和解释&#xff1a; abstract 方法不能是 static&#xff1a; abstract 方法必须被子类实现&#xff0c;而 static 方法是与类相关的&…

使用vscode插件du-i18n处理前端项目国际化翻译多语言

前段时间我写了一篇关于项目国际化使用I18n组件的文章&#xff0c;Vue3 TS 使用国际化组件I18n&#xff0c;那个时候还没真正在项目中使用&#xff0c;需求排期还没有定&#xff0c;相当于是预研。 当时就看了一下大概怎么用&#xff0c;改了一个简单的页面&#xff0c;最近需…

【Python系列】Python 中的日期和时间处理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Vue3模拟国足18强赛抽签

Vue3国足18强赛抽签 国足遇到这个对阵&#xff0c;能顺利出现吗&#xff1f; 1、系统演示 Vue3模拟国足18强赛抽签 2、关键代码 开始抽签 <script setup> import FenDang from "/components/chouqian/FenDang.vue"; import {ref} from "vue";le…

赶紧收藏!2024 年最常见 20道设计模式面试题(三)

上一篇地址&#xff1a;赶紧收藏&#xff01;2024 年最常见 20道设计模式面试题&#xff08;二&#xff09;-CSDN博客 五、建造者模式&#xff1a;建造者模式如何解决复杂对象的构建问题&#xff1f; 建造者模式&#xff08;Builder Pattern&#xff09;是一种对象创建型设计…

看完轻松解决家里灰尘毛絮多难题?除粉尘的空气净化器品牌分享

家里的空气中弥漫着灰尘和毛絮&#xff0c;让人呼吸不畅&#xff0c;也影响着家人的健康。灰尘中含有各种有害物质&#xff0c;如细菌、病毒、花粉等&#xff0c;长期吸入会导致呼吸道疾病、皮肤过敏等问题。尤其是对于有宠物、孩子、过敏人群来说&#xff0c;空气质量更是至关…

关于办公软件的使用

第一部分&#xff1a; 常用函数的使用 在使用的地方&#xff0c;输入SUM(B2:F2)回车 第二部分&#xff1a; 自定义函数的使用 1、打开 宏编辑 2、 自定义函数方法 3、自定义函数的使用和常用函数一样&#xff1a; 在使用的地方&#xff0c;输入计算面积(A3&#xff0c;B3)…

游戏试玩站打码zq平台系统可运营的任务网源码

安装说明 1.恢复数据&#xff1b; 2.数据连接库配置路径&#xff1a;protected\config\mail.php 文件中修改第60行 &#xff08;记得不要用记事本修改&#xff0c;否则可能会出现验证码显示不了问题&#xff0c;建议用Notepad&#xff09; 3.浏览器访问输入 127.0.0.2 显示界…

Hype4.0 for Mac软件下载-Hype for Mac HTML5 创作工具下载附加详细安装步骤

Hype 4 Pro Mac正式版是款功能实用的动画创作工具。Hype 4 Pro Mac最新版可以帮您轻松创建令人惊叹的动画和交互式网页内容。并且Hype 4 Pro Mac还可被设计师用来创建动画&#xff0c;为网页、信息图形、演示文稿、数字杂志、广告、iBooks、教育内容、应用程序原型、作品集、动…

C# —— 字典

简介 字典: 包含一个key(键)和这个key所对应的value(值),字典是无序的,key是唯一的&#xff0c;可以根据key获取值。可以吧键当成数组的索引值进行理解 <> 泛型 定义一个字典 new Dictionary<key的类型, value值的类型>() var dic new Dictionary<string, s…

Flume基础教程

Apache Flume教程 资料来源&#xff1a;Apache Flume - Introduction (tutorialspoint.com) Flume是一个标准的、简单的、健壮的、灵活的、可扩展的工具&#xff0c;用于将从各种数据生产者(web服务器)中所产生的数据抽取到Hadoop中。在本教程中&#xff0c;我们将使用简单的…

软件测试技术(一):软件测试流程

软件测试流程 软件测试流程如下&#xff1a; 测试计划测试设计测试执行 单元测试集成测试确认测试系统测试验收测试回归测试验证活动 测试计划 测试计划由测试负责人来编写&#xff0c;用于确定各个测试阶段的目标和策略。这个过程将输出测试计划&#xff0c;明确要完成的测…

ch552g使用torch-pad测试触摸按键遇到的问题

基本工作原理 通过设置好功能在寄存器和控制寄存器检测引脚输入的值。 实际检测阶段分为3个步骤&#xff1a;第一阶段&#xff1a;选择需要检测的阶段&#xff0c;选择扫描周期1或2ms&#xff0c;开启触摸按键中断&#xff0c;然后在87us内为充电准备阶段&#xff0c;87us内数…