0

0

C++怎么实现一个笛卡尔树_C++数据结构与RMQ问题的高效解法

穿越時空

穿越時空

发布时间:2025-11-24 13:10:02

|

253人浏览过

|

来源于php中文网

原创

笛卡尔树通过结合二叉搜索树和堆性质,将RMQ问题转化为LCA问题,利用单调栈在O(n)时间内构建,并配合DFS与稀疏表实现O(1)查询,适用于静态数据的高效区间最值查询。

c++怎么实现一个笛卡尔树_c++数据结构与rmq问题的高效解法

笛卡尔树(Cartesian Tree)是一种结合了二叉搜索树和堆性质的数据结构,常用于解决RMQ(Range Minimum/Maximum Query,区间最值查询)问题。通过将RMQ转化为LCA(Lowest Common Ancestor,最近公共祖先)问题,笛卡尔树能在线性预处理后实现O(1)查询,是C++中高效处理静态RMQ的重要手段。

笛卡尔树的定义与性质

笛卡尔树满足两个关键性质:

  • 二叉搜索树性质:中序遍历结果等于原数组顺序。
  • 最小堆性质:每个节点的值小于等于其子节点的值(最小笛卡尔树)。

构建完成后,原数组任意区间的最小值对应笛卡尔树中该区间对应节点的LCA。这使得RMQ问题可通过LCA求解。

线性时间构建笛卡尔树

利用单调可以在O(n)时间内完成构建。核心思路是维护一个值递增的栈,逐个插入元素并调整树结构。

立即学习C++免费学习笔记(深入)”;

示例代码:
#include 
#include 
using namespace std;

struct Node { int val, idx; Node left, right; Node(int v, int i) : val(v), idx(i), left(nullptr), right(nullptr) {} };

Node* buildCartesianTree(const vector& arr) { int n = arr.size(); if (n == 0) return nullptr;

vectorzuojiankuohaophpcnNode*youjiankuohaophpcn nodes;
for (int i = 0; i zuojiankuohaophpcn n; ++i)
    nodes.push_back(new Node(arr[i], i));

stackzuojiankuohaophpcnNode*youjiankuohaophpcn stk;
for (int i = 0; i zuojiankuohaophpcn n; ++i) {
    Node* lastPop = nullptr;
    while (!stk.empty() && stk.top()-youjiankuohaophpcnval youjiankuohaophpcn arr[i]) {
        lastPop = stk.top();
        stk.pop();
    }
    if (!stk.empty())
        stk.top()-youjiankuohaophpcnright = nodes[i];
    if (lastPop)
        nodes[i]-youjiankuohaophpcnleft = lastPop;
    stk.push(nodes[i]);
}

Node* root = nullptr;
while (!stk.empty()) {
    root = stk.top();
    stk.pop();
}
return root;

}

该方法确保每个节点最多入栈出栈一次,总时间复杂度为O(n)。

万彩AI
万彩AI

多功能AI创作工具合集,支持AI写作、AI换脸、AI数字人等

下载

结合RMQ的高效查询方案

构建笛卡尔树后,RMQ(a, b)等价于查找节点a和b在树中的LCA。可通过以下步骤实现高效查询:

  • 对笛卡尔树进行DFS,记录访问节点序列、深度序列和首次出现位置。
  • 将LCA问题转化为新的RMQ问题(在深度序列上找最小值)。
  • 使用稀疏表(Sparse Table)预处理深度序列,实现O(1)查询。

整体流程:原数组 → 构建笛卡尔树 → DFS生成Euler Tour → ST表预处理 → O(1) RMQ查询。

实际应用场景与注意事项

笛卡尔树适用于静态或半静态数据的RMQ场景,如:

  • 滑动窗口最小值
  • 直方图最大矩形面积
  • 字符串算法中的某些优化

注意点:

  • 若数组有重复元素,需定义索引优先规则以保证堆性质唯一性。
  • 动态更新代价较高,不适合频繁修改的场景。
  • 指针操作易出错,可改用数组下标模拟树结构提升稳定性。

基本上就这些,掌握构建和转化思想后,配合ST表就能高效解决多数RMQ问题。

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

253

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

206

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1463

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

613

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

548

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

542

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

159

2025.07.29

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

77

2025.08.07

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

3

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 6.3万人学习

C 教程
C 教程

共75课时 | 3.9万人学习

C++教程
C++教程

共115课时 | 11.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号