AcWing 1644. 二叉树中的最低公共祖先 题解 线性dp 倍增算法 前序中序构造二叉树

二叉树中的最低公共祖先

题目描述

树中两个结点 U 和 V 的最低公共祖先(LCA)是指同时具有 U 和 V 作为后代的最深结点。给定二叉树中的任何两个结点,请你找到它们的 LCA。

输入描述

第一行包含两个整数 M 和 N ,分别表示询问结点对数以及二叉树中的结点数量。
接下来两行,每行包含 N 个不同的整数,分别表示二叉树的中序和前序遍历。保证二叉树可由给定遍历序列唯一确定。
接下来 M 行,每行包含两个整数 U 和 V ,表示一组询问。

输出描述

对于每对给定的 U 和 V ,输出一行结果:
如果 U 和 V 的 LCA 是 A ,且 A 不是 U 或 V ,则输出 “LCA of U and V is A.”
如果 U 和 V 的 LCA 是 A ,且 A 是 U 或 V 中的一个,则输出 “X is an ancestor of Y.” ,其中 X 表示 A , Y 表示另一个结点。
如果 U 或 V 没有在二叉树中找到,则输出 “ERROR: U is not found.” 或 “ERROR: V is not found.” 或 “ERROR: U and V are not found.”。

用例输入

6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99

用例输出

LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

数据规模与约定

所有结点权值均在 int 范围内。
1 ≤ M ≤ 1000,1 ≤ N ≤ 10000。

题目链接

AcWing1644——传送门

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;const int maxn = 1e4 + 6;vector<int> e[maxn];    // 以第i个节点为起点的有向边
int depth[maxn];        // 第i个节点的深度
int ancestor[maxn][23]; // ancestor[i][j]表示节点i的2^j级祖先
int lg[maxn];           // 预处理第i个节点的lg值void add(int x, int y) // 加有向边函数
{e[x].push_back(y);
}void dfs(int u, int fath) // dfs计算深度和祖先
{ancestor[u][0] = fath;                                    // 第1级祖先即为父亲depth[u] = depth[fath] + 1;                               // 深度为父亲深度+1for (int j = 1; j <= lg[depth[u]]; j++)                   // 计算该节点的2^j级祖先ancestor[u][j] = ancestor[ancestor[u][j - 1]][j - 1]; // 祖先的转移方程,u的2^j祖先等于u的2^(j-1)祖先的2^(j-1)祖先for (int i = 0; i < e[u].size(); i++)                     // 递归子节点{int v = e[u][i];if (fath != v)dfs(v, u);}
}map<int, int> idx; // 离散化后的下标
map<int, int> num; // 下标所对应的原来的值void LCA(int x, int y) // 计算x和y的LCA
{// 将x和y先记录下来,便于输出答案int u = x;int v = y;// 将x和y转化为离散后的下标x = idx[x];y = idx[y];bool tag = 0;            // 记录是否发生了交换if (depth[x] < depth[y]) // 让x为深度更大(或相等)的那一个{swap(x, y);tag = 1;}while (depth[x] > depth[y]) // 将x提到与y相同深度x = ancestor[x][lg[depth[x] - depth[y]] - 1];if (x == y){if (tag == 0)cout << v << " is an ancestor of " << u << "." << '\n';elsecout << u << " is an ancestor of " << v << "." << '\n';return;}for (int k = lg[depth[x]] - 1; k >= 0; k--) // 倍增跳跃if (ancestor[x][k] != ancestor[y][k])x = ancestor[x][k], y = ancestor[y][k];cout << "LCA of " << u << " and " << v << " is " << num[ancestor[x][0]] << "." << '\n';return;
}map<int, int> mp;
int lc[maxn];
int rc[maxn];
int traversal(int pre_st, int pre_end, int in_st, int in_end, vector<int> &in, vector<int> &pre)
{int cur_len = pre_end - pre_st; // 当前区间长度if (cur_len == 0)return 0;int root = pre[pre_st]; // 找到根节点if (cur_len == 1)return root;int pos = mp[root];    // 根位置int len = pos - in_st; // 左子树长度// 递归构造左子树和右子树lc[root] = traversal(pre_st + 1, pre_st + len + 1, in_st, pos, in, pre);rc[root] = traversal(pre_st + len + 1, pre_end, pos + 1, in_end, in, pre);return root;
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int n, m, root; // 节点个数,询问个数,根节点cin >> m >> n;vector<int> in(n);vector<int> pre(n);map<int, bool> exist; // 记录某点是否存在// 中序序列for (int i = 0; i < n; i++){cin >> in[i];exist[in[i]] = 1;}// 离散化各个点为1~nint i = 1;for (auto it = exist.begin(); it != exist.end(); it++, i++){idx[it->first] = i;num[i] = it->first;}// 将中序序列改为离散后的下标for (int i = 0; i < n; i++){in[i] = idx[in[i]];}// 记录在中序序列中的位置for (int i = 0; i < n; i++){mp[in[i]] = i;}// 前序序列for (int i = 0; i < n; i++){cin >> pre[i];}// 将前序序列改为离散后的下标for (int i = 0; i < n; i++){pre[i] = idx[pre[i]];}// 构造二叉树root = traversal(0, n, 0, n, in, pre);// 记录树中的边for (int i = 1; i <= n; i++){if (lc[i] != 0){add(i, lc[i]);add(lc[i], i);}if (rc[i] != 0){add(i, rc[i]);add(rc[i], i);}}// 预处理每个深度值的lg值for (int i = 1; i <= n; ++i)lg[i] = lg[i - 1] + (1 << lg[i - 1] == i); // 非常厉害的转移方程// 预处理节点i的2^j级祖先dfs(root, 0);// 处理询问int x, y;for (int i = 1; i <= m; ++i){cin >> x >> y;if (exist[x] == 0 && exist[y] == 0){cout << "ERROR: " << x << " and " << y << " are not found." << '\n';}else if (exist[x] == 0){cout << "ERROR: " << x << " is not found." << '\n';}else if (exist[y] == 0){cout << "ERROR: " << y << " is not found." << '\n';}else{LCA(x, y);}}return 0;
}

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

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

相关文章

AlphaFold3: Google DeepMind的的新突破

AlphaFold 3的论文今天在Nature期刊发表啦!这可是AI在生物领域最厉害的突破的最新版本。AlphaFold-3的新招就是用扩散模型去"画出"分子的结构。它一开始先从一团模模糊糊的原子云下手,然后慢慢透过去噪把分子变得越来越清楚。 Alphafold3 我们活在一个从Llama和Sora那…

C# WinForm —— 12 ListBox绑定数据

ListBox加载大量数据时&#xff0c;避免窗体闪烁的方法&#xff1a; 在加载语句的前后分别加上 BeginUpdate()方法 和 EndUpdate()方法 指定一个集合为绑定的数据源 1. 首先&#xff0c;右键项目&#xff0c;添加类 2. 在新建的类文件中添加属性值信息 3. 构建初始化的对象…

跟TED演讲学英文:Teachers need real feedback by Bill Gates

Teachers need real feedback Link: https://www.ted.com/talks/bill_gates_teachers_need_real_feedback Speaker: Bill Gates Date: May 2013 文章目录 Teachers need real feedbackIntroductionVocabularyTranscriptSummary后记 Introduction Until recently, many teach…

MYSQL-8.调优

性能优化思维 整体思维 木桶效应&#xff1a;系统的性能符合木桶效应&#xff08;一个木桶能装多少水&#xff0c;取决于木桶中最短的那块木板&#xff09;&#xff0c;所以性能优化需要从多个方面去考虑&#xff0c;如架构优化、业务优化、前端优化、中间件调优、网关优化、…

Python_AI库 Pandas的loc和iloc的区别与使用实例

Python中Pandas的loc和iloc的区别与使用实例 在Pandas中&#xff0c;loc和iloc是两个常用的方法&#xff0c;用于基于标签&#xff08;label&#xff09;和整数位置&#xff08;integer location&#xff09;来选择数据。尽管两者在功能上有重叠&#xff0c;但它们在用法和性能…

去哪儿网机票服务请求体bella值逆向

作者声明&#xff1a;文章仅供学习交流与参考&#xff01;严禁用于任何商业与非法用途&#xff01;否则由此产生的一切后果均与作者无关&#xff01;如有侵权&#xff0c;请联系作者本人进行删除&#xff01; 一、加密定位 直接全局搜索bella&#xff0c;在可疑的地方下断&…

汇编--栈和寄存器

栈 栈是一种运算受限的线性表&#xff0c;其限定仅在表尾进行插入和删除操作的线性表&#xff0c;表尾也被叫做栈顶。简单概括就是我们对于元素的操作只能够在栈顶进行&#xff0c;也造就了其先进后出的结构特性。 栈 这种内存空间其实本质上有两种操作&#xff1a;将数据放入…

在Ubuntu安装RPM文件

Ubuntu软件源包含数千个deb软件包&#xff0c;可以从Ubuntu软件中心或使用apt命令行安装。 Deb是所有基于Debian的Linux发行版&#xff0c;例如包括Ubuntu&#xff0c;Linux mint等发行版使用的安装包格式。 如果某些软件在Ubuntu软件源中不可用&#xff0c;可以通过启用适当的…

物联网实战--平台篇之(五)账户界面

目录 一、界面框架 二、首页(未登录) 三、验证码登录 四、密码登录 五、帐号注册 六、忘记密码 本项目的交流QQ群:701889554 物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html 物联网实战--驱动篇https://blog.csdn.net/ypp240124016/cat…

物联网网关制造生产全流程揭秘!

如果您正有开发和定制物联网网关的计划&#xff0c;找一个专业的物联网设备厂商协助您制造生产物联网网关可以节省大量时间和成本&#xff0c;可以让您能专注于当前核心业务&#xff0c;而无需将精力过多地投入到自己不擅长的领域。 当然&#xff0c;了解物联网网关的测试和制…

HSA-42014和安泰ATA-4014C高压功率放大器对比

企业背景&#xff1a; Aigtek是一家来自中国的专业从事测量仪器研发、生产和销售的高科技企业。公司主要研发和生产功率放大器、功率放大器模块、功率信号源、计量校准源等产品。核心团队主要是来自西安交通大学及西北工业大学的专家教授等联合组成研发团队&#xff0c;目前拥有…

OPC UA(二)

一、配置PC Station 在TIA博途软件平台中配置PC Station&#xff0c;见&#xff08;一&#xff09; 二、使用OPC Scout V10测试通信结果 1. 添加OPC UA Server站点 1.1启动OPC Scout V10 1.2 打开OPC Scout V10&#xff0c;在 Server explorer窗口&#xff0c;查找UA serv…

Linux流量分析工具 | nethogs

在应急过程中&#xff0c;经常会遇到应用访问缓慢&#xff0c;网络阻塞的情况&#xff0c;分析原因可能会想到存在恶意程序把带宽占满的可能。通过这样一个小工具可以快速定位异常占用带宽程序的路径、PID、占用流量大小或是排除由带宽占满导致服务器缓慢的猜想。 一、简介 Ne…

Python学习——环境搭建

Python 介绍 Python&#xff08;英国发音&#xff1a;/ˈpaɪθən/ 美国发音&#xff1a;/ˈpaɪθɑːn/&#xff09;是一种广泛使用的解释型、高级编程、通用型编程语言&#xff0c;由吉多范罗苏姆创造&#xff0c;第一版发布于1991年。可以视之为一种改良&#xff08;加入…

DDD领域驱动模型设计

醍醐灌顶了朋友们 第一次写ddd还是 一路走来 丢失了东西 现在倒是也能找回来 只是有点可惜了 选择比努力更重要 独立功能 应用层&#xff1a;组织业务逻辑 领域&#xff1a;实体对象领域&#xff0c;业务核心 数据仓库&#xff1a; 不影响业务封装了数据操作&#xff0c;…

嵌入式开发九:STM32时钟系统

时钟对于单片机来说是非常重要的&#xff0c;它为单片机工作提供一个稳定的机器周期从而使系统能够正常运行。时钟系统犹如人的心脏&#xff0c;一旦有问题整个系统就崩溃。我们知道 STM32 属于高级单片机&#xff0c;其内部有很多的外设&#xff0c;但不是所有外设都使用同一时…

云计算安全扩展要求解析

云计算技术的信息系统&#xff0c;称为云计算平台&#xff0f;系统。 云计算平台&#xff0f;系统由设施、硬 件、资源抽象控制层、虚拟化计算资源、软件平台和应用软件等组成。 软件即服务(SaaS)、平台即服务 (PaaS) 、基础设施即服务ClaaS)是三种基本的云计算服务模式。在不同…

实验10配置 IPv4 和 IPv6 静态和 默认路由(课内实验)

上面这个是实验描述 下面是给的实验图 接下来我们跟着实验一步一步进行下去 第 1 部分&#xff1a;配置 IPv4 静态和 浮动静态默认路由配置ipv4静态路由&#xff1a;配置 IPv4静态和 浮动静态默认路由 步骤 1&#xff1a;配置一条 IPv4 静态 默认路由。在 Edge_Router 上&am…

ASP.NET校园新闻发布系统的设计与实现

摘 要 校园新闻发布系统是在学校区域内为学校教育提供资源共享、信息交流和协同工作的计算机网络信息系统。随着网络技术的发展和Internet应用的普及&#xff0c;互联网已成为人们获取信息的重要来源。由于现在各大学校的教师和学生对信息的需求越来越高&#xff0c;校园信息…

Linux-笔记 修改开发板默认时区

1. 时区文件 使用命令date -R查看当前的默认时区&#xff0c;date - R命令会自动解析/etc/localtime 文件&#xff0c;而该文件又是指向“ /usr/share/zoneinfo/$主时区/$次时区 ”&#xff0c;当需要更改到指定的时区只要将/etc/localtime 文件软链接到 ”/usr/share/zoneinf…