线段树+RMQ问题第二弹
线段树+RMQ问题第二弹
上篇文章讲到了基于Sparse Table 解决 RMQ 问题,不知道大家还有没有印象,今天我们会从线段树的方法对 RMQ 问题再一次讨论。
正式介绍今天解决 RMQ 问题的方法之前,我先对 RMQ 问题的概念再一次进行说明。RMQ (Range Minimum/Maximum Query ):中文名为“区间最值查询”。RMQ 问题指的是给定一段区间,针对给定区间进行若干次查询,每次给出不同的待查询子区间范围,要求返回子区间内的最大值或者最小值。
RMQ 问题可以看作是线段树的一个应用,本来今天的主角是 RMQ 问题,但我思前想后觉得草草解释线段树或者只展示RMQ一个方面的应用留个小尾巴有点意犹未尽,之前没有接触过线段树的朋友也会觉得云里雾里,因此我改变主意决定以线段树的基本概念和应用作为今天的主要内容,RMQ问题的解决作为整篇文章的一个实例,下面就要进入主题了。
线段树是什么?线段树是一种完美的树,这种树对于处理区间问题有相当高的效率。线段树满足这样一些特点:
一、是一棵完全二叉树,除最后一层之外其余各层均是满的,所有的叶节点均排布在最后一层,所有的节点不是叶节点就是拥有两棵子树的节点。
二、每个节点维护一段区间,其中根节点维护的是整个区间,其余节点均维护的是直接父节点的二分之一区间,也就意味着将父节点维护的区间二等分分别分给左右两个孩子维护。
三、根据节点维护的数据不同,线段树可以实现不同的功能。
四、并非所有的区间问题都可以用线段树来解决。
这样不形象的用文字描述就想让没接触过的人了解线段树实在有点强人所难,我还是画一张丑图来说明一下吧。如下图所示:
以求 RMQ 问题为例我们来深入了解一下有关线段树的性质,假设本篇文章我们的要求是求区间最小值。
由上图可知,该图中的线段树维护的是 n = 8 的区间的数据,每个节点存储的是所维护区间内的最小值,该线段树的深度为 L 。通常情况下整个线段树各节点的值会存储在数组里边,因此我们需要知道线段树的节点数。假设 区间的元素个数为 n ,线段树的深度为 L ,线段树的节点数为 m 。
由上图可知三者满足的关系为:
L = log n +1(对数以 2 为底);即 2^(L-1) = n
m = 2^0 + 2^1 + 2^2 + 2^3 + ......+ 2^( L - 1)
m =( 2^0 + 2^0 )+ 2^1 + 2^2 + 2^3 +...... + 2^( L-1) -1
m = (2^1 + 2^1) + 2^2 + 2^3 +......+ 2^(L-1) - 1
... ...
m = 2^(L-1) + 2^(L-1) -1
m = n + n -1
m = 2n-1
由上面的推导过程可以知道,m = 2n-1是妥妥的。没求证之前,可能很多人看到线段树的图之后,都会觉得规模应该是 O(n log n),虽然不知道这种错觉的理由是什么,但是知道了一点,以后凡事都需要自己亲自验证一番才能彻底打消错误的念头。这也就意味着对线段树的初始化是O(n)的时间复杂度。
现在我们来看一下求区间最值具体是怎样实现的。首先我们知道线段树上存储的是一些固定区间的最值,因此我们要求一些自定义区间的最值时,需要同时结合线段树上的若干个连续区间的多个最值,在其中选择最小的作为最后的结果,由于将整个区间分成若干子区间分别求最值最后合并结果的方法对最后结果的正确性没有影响,因此存在实现上的可行性。那么对于自定义的一个区间,在线段树上具体需要选取哪些区间呢?我们需要选取的是能够完全被自定义区间覆盖的那些区间。对于线段树上的任何一个区间,可能执行的操作有三个:
若该区间中的所有元素均包含在自定义区间中,那么直接返回线段树上存储的该区间最值。
若该区间的所有元素中任何一个元素都不曾出现在自定义区间中,那么自定义区间的最值一定不会来自该区间,这时候返回一个不影响结果判断的值即可。
若该区间既不能被自定义区间完全包含,又存在若干元素包含在自定义区间中,那么递归的对该区间对应的两个子区间分别执行这三个判断。
大概思路就是如此。
虽然将普通区间改造为线段树来维护没有增加过多的任务量,由上面的分析可以知道这么做的效果却是很惊人的,因为利用线段树求区间最值的时候,在树的每一层至多需要访问两个节点,由上至下共 L = log n +1层,也就意味着,找到一个区间的最值需要访问的节点数 至多都不会超过 2 * L - 1 ,因此查找一次区间最值时间复杂度稳定在 O( log n)的时间复杂度,这可是个惊人的发现呢。
线段树的另一个比较有名的应用就是修改区间上某一位置的值,可以从线段树的最底层开始修改,由于在任何一层每个元素只可能出现在一个区间,因此修改一个值的时间复杂度恒为O(log n)。
线段树的两个比较常见的应用都在这里,理论描述上面已经给出,接下来我将核心代码部分附上供大家对细节进行推敲。图片看不清楚的朋友可打开网页http://paste.ubuntu.com/25418076/查看网页版的代码。
今天的分享就到这里,有朋友发现文章中写的不合适的地方可以直接在下方留言区留言纠正。
没有关注公众号的朋友,可以识别下方二维码关注我。
线段树+RMQ问题第二弹的更多相关文章
- HDU 1754 I Hate It 线段树RMQ
I Hate It Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=175 ...
- 《白书》上线段树RMQ的实现
白书上的线段树RMQ实现,自己重写了一遍: #include <bits/stdc++.h> using namespace std; const int MAXN=1<<17 ...
- ACM学习历程—HDU 5289 Assignment(线段树 || RMQ || 单调队列)
Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fro ...
- UVA 11235 Frequent values 线段树/RMQ
vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释**************** ...
- dutacm.club_1094_等差区间_(线段树)(RMQ算法)
1094: 等差区间 Time Limit:5000/3000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)Total ...
- Hlg 1832 【线段树 && RMQ】.cpp
题意: 在给出的区间内求出最大买进卖出的差价. 思路: 对于弱数据:维护一个从左到右的最大差价和最小值.即当发现当前值比最小值小的时候更新最小值,否则看一下当前值与之前最小值的差价是否比最大差价大,是 ...
- 单点更新线段树 RMQ
D. Xenia and Bit Operations time limit per test 2 seconds memory limit per test 256 megabytes input ...
- CSU 1809 - Parenthesis - [前缀和+维护区间最小值][线段树/RMQ]
题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809 Bobo has a balanced parenthesis sequenc ...
- PKU 2823 Sliding Window(线段树||RMQ||单调队列)
题目大意:原题链接(定长区间求最值) 给定长为n的数组,求出每k个数之间的最小/大值. 解法一:线段树 segtree节点存储区间的最小/大值 Query_min(int p,int l,int r, ...
随机推荐
- JAVA基础----持续更新
1.基本数据类型 - 整数型:byte short int long 默认为int 计算时需要转换 - 浮点型:float double 默认为double - 布 ...
- PYQT4 : QSystemTrayIcon练习
照着demo自己做了一遍,练练手 import sys from PyQt4 import QtGui from PyQt4 import QtCore class SysTray(QtGui.QDi ...
- 420小时学习代码之后:如何教你免费自学Python
原文地址:learning-to-code-420-hours-later-how-to-teach-yourself-python-for-free 说明:有些网址需要FQ. 大约在1.5年前,我开 ...
- 介绍下Python的两个标准库 os 和 sys
import sysprint(sys.path) #python 2 中报错 ....,打印的是绝对路径(***\\python\\lib\\site-packages# 第三方库,后退一级为标准库 ...
- 开源的API集成测试工具 v0.1.2 - 增强体验
Hitchhiker 是一款开源的 Restful Api 集成测试工具,你可以在轻松部署到本地,和你的team成员一起管理Api. 详细介绍请看: http://www.cnblogs.com/br ...
- windows.onload和 document.ready区别
在Jquery里面,我们可以看到两种写法:$(function(){}) 和$(document).ready(function(){}) 这两个方法的效果都是一样的,都是在dom文档树加载完之后执行 ...
- C#后台调用浏览器打开下载连接地址的三种方法
一.从注册表中读取到本地计算机默认浏览器,然后调用下载. private void button1_Click(object sender, EventArgs e) { //从注册表 ...
- Java并发之线程
在前面我们介绍的一些内容中,我们的程序都是一条执行流,一步一步的执行.但其实这种程序对我们计算机的资源的使用上是低效的.例如:我们有一个用于计算的程序,主程序计算数据,在计算的过程中每得到一个结果就需 ...
- [自制操作系统] BMP格式文件读取&图形界面系统框架/应用接口设计
本文将介绍在本人JOS中实现的简单图形界面应用程序接口,应用程序启动器,以及一些利用了图形界面的示例应用程序. 本文主要涉及以下部分: 内核/用户RW/RW调色板framebuffer共享区域 8bi ...
- 团队作业8——第二次项目冲刺(Beta阶段)--第六天
一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 学号 成员 贡献比 201421123001 廖婷婷 16% 201421123002 翁珊 16% 201421123004 ...