RMQ问题(Sparse-Table算法)
范围最值问题(Range Minimum/maximum Query,RMQ)。给出一个哪个元素的数组A1,A2,...An,要求设计一个数据结构,支持查询操作:计算min(AL,AL+1,...,AR)或者max(AL,AL+1,...,AR)。每次都用一个循环来计算显然不够快,这里介绍Tarjan的Sparse-Table算法,它的预处理时间是O(nlogn),查询时间是O(1),因此效率更高。
令d(i,j)表示从i开始的,长度为2j的一段元素的最小值,可以用递推的方法计算d(i, j): d(i, j) = min(d(i, j - 1), d(i + 2 j -1, j - 1)}。
因为长度是2j,因此d数组的大小不超过nlogn。递推代码如下:
void RMQ_init(const vector<int>& A) {
int n = A.size();
for(int i = ; i < n; i++) {
d[i][] = A[i];//以i开头,长度为1的最小值是A[i]
} for(int j = ; ( << j) <= n; j++) {//再区间范围内枚举次方
for(int i = ; i + ( << j) - < n; i++) {//枚举每一个开头,直到没有长度为2的j的区间
d[i][j] = min(d[i][j - ], d[i + ( << j) - ][j - ]);
}
}
}
查询时另k为满足2k<=R-L+1的最大整数,则以L开头、以R结尾的两个长度为2k的区间合起来也就覆盖了查询区间[L, R]。查询代码如下:
int RMQ_query(int L, int R) {
int k = ;
while(( << (k + )) <= R - L + ) k++;//若2的k+1次方<= R - L + 1,则k还可以加1
return min(d[L][k], d[R - ( << k) + ][k]);
}
下面看一道例题:UVa 11235 Frequent values
题意是给出一个非降序的整数数组a1,a2,a3...a4,a5,你的任务是对于一系列询问(i, j),回答在此区间中出现次数最多的值所出现的次数。
刚看可能觉得和区间最值查询没有什么联系,我们仔细分析一下,由于数组是非降序的,可以知道数值相同的元素一定是聚在一起的,我们将整个数组进行游程编码,比如-1,1,1,2,3,3,可以写成(-1,1),(1,2),(2,1),(3,2),其中(a,b)表示有b个连续的a。我们用value[i]和count[i]分别表示第i段的数值和出现的次数,num[p],left[p],right[p],分别表示位置p所在段的编号和左右端点位置。接下来每次查询(L,R)的结果就是以下三个部分的最大值:
从L到L所在段的结束处的元素个数(即right[L] - L + 1)
从R所在段的开始处到R处的元素个数(即R - left[R] + 1)
中间第num[L] + 1段到第num[R] - 1段的count的最大值(终于用到区间查询最大值,在(num[L] + 1, num[R] - 1)中的最大值)
需要注意的特殊情况是:如果L和R在同一段中,则答案是R - L + 1。
具体参考代码如下:
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std; const int maxn = + ;
const int maxlog = ; struct RMQ {
int d[maxn][maxlog];//以i为开头,长度为1<<j的最值
void init(const vector<int>& A) {
int n = A.size();
for(int i = ; i < n; i++)
d[i][] = A[i];//初始化
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i + ( << j) - < n; i++) {
d[i][j] = max(d[i][j - ], d[i + ( << (j - ))][j - ]);
}
}
}
int query(int L, int R) {
int k = ;
while(( << (k + )) <= R - L + ) k++;
return max(d[L][k], d[R - ( << k) + ][k]);
}
}; int a[maxn], num[maxn], right[maxn], left[maxn];
RMQ rmq; int main()
{
int n, q;
while(scanf("%d%d", &n, &q) == && n != ) {
for(int i = ; i < n; i++) {
scanf("%d", &a[i]);
}
a[n] = a[n - ] + ;//放置一个哨兵 int start = -;
vector<int> count;
for(int i = ; i <= n; i++) {
if(i == || a[i] > a[i - ]) {//新一段的开始
if(i > ) {
count.push_back(i - start);
for(int j = start; j < i; j++) {
num[j] = count.size() - ;
left[j] = start;
right[j] = i - ;
}
}
start = i;
}
}
rmq.init(count);//将每段值出现的次数作为查询的内容 int L, R, ans;
while(q--) {
scanf("%d%d", &L, &R);
L--;R--;
if(num[L] == num[R])
ans = R - L + ;
else {
ans = max(R - left[R] + , right[L] - L + );
if(num[L] + < num[R])
ans = max(ans, rmq.query(num[L] + , num[R] - ));
}
printf("%d\n", ans);
}
}
return ;
}
RMQ问题(Sparse-Table算法)的更多相关文章
- RMQ(ST(Sparse Table))(转载)
1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...
- codeforce 359D 二分+ 动态规划(sparse table)
原题链接:http://codeforces.com/problemset/problem/359/D 思路:首先对符合题目的长度(r-l)从0到n-1进行二分查找,对每一个长度进行check,看是否 ...
- RMQ ---- ST(Sparse Table)算法
[概述] RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返 ...
- 51NOD1174 区间最大数 && RMQ问题(ST算法)
RMQ问题(区间最值问题Range Minimum/Maximum Query) ST算法 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度 ...
- 一维二维Sparse Table
写在前面: 记录了个人的学习过程,同时方便复习 Sparse Table 有些情况,需要反复读取某个指定范围内的值而不需要修改 逐个判断区间内的每个值显然太浪费时间 我们希望用空间换取时间 ST表就是 ...
- RMQ问题之ST算法
RMQ问题之ST算法 RMQ(Range Minimum/Maximum Query)问题,即区间最值问题.给你n个数,a1 , a2 , a3 , ... ,an,求出区间 [ l , r ]的最大 ...
- poj 3264 区间最大最小值 RMQ问题之Sparse_Table算法
Balanced Lineup Time Limit: 5000 MS Memory Limit: 0 KB 64-bit integer IO format: %I64d , %I64u Java ...
- 基于稀疏表(Sparse Table)的RMQ(区间最值问题)
在RMQ的其他实现方法中,有一种叫做ST的算法比较常见. [构建] dp[i][j]表示的是从i起连续的2j个数xi,xi+1,xi+2,...xi+2j-1( 区间为[i,i+2j-1] )的最值. ...
- ST (Sparse Table:稀疏表)算法
1541:[例 1]数列区间最大值 时间限制: 1000 ms 内存限制: 524288 KB提交数: 600 通过数: 207 [题目描述] 输入一串数字,给你 MM 个询问 ...
- 散列表(hash table)——算法导论(13)
1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...
随机推荐
- leveldb 学习记录(六)SSTable:Block操作
block结构示意图 sstable中Block 头文件如下: class Block { public: // Initialize the block with the specified con ...
- Linux配置ntp时间服务器(全)
时间服务器作用: 大数据产生与处理系统是各种计算设备集群的,计算设备将统一.同步的标准时间用于记录各种事件发生时序, 如E-MAIL信息.文件创建和访问时间.数据库处理时间等. 大数据系统内不同计算设 ...
- SQLite3命令操作大全
SQLite3命令操作大全 SQLite库包含一个名字叫做sqlite3的命令行,它可以让用户手工输入并执行面向SQLite数据库的SQL命令.本文档提供一个样使用sqlite3的简要说明. 一.ql ...
- bgfx入门练习1——切换图形API驱动模式DX与OpenGL
翻了下上次编译bgfx是去年2月份的事了,最近正好想试试DX,OpenGL双驱动,看Urho3D和Klayge光封装就头痛,人又懒,写OpenGL时也基本glfw,于是想到bgfx,不如再试试. 发现 ...
- 让IE8支持html5中的video标签
这是一篇综合几个前辈的解决方案. 使用video的时候,要遇到的问题. ①不兼容ie9及其以下版本 在<head>里添加两行, 参考张鑫旭前辈的博客,但是在ie8中薄播放. <!-- ...
- Html5与Css3知识点拾遗(四)
web图像 JPEG:适用于大多数照片,颜色较多,可接受质量损失的图像 PNG-8:适用标识.重复的图案以及其他颜色较少的图像或具有连续颜色的图像 PNG-24:不支持颜色更多的图像,适用与颜色丰富且 ...
- 【python接口自动化测试教程】00---00章节就代表开篇吧
今天突然想写个接口测试教程,由于本人是初级的比小白稍微好那么一丢丢,所以不知道能不能坚持下来 写的不对的地方还请大咖指教 先去忙自己的工作了,忙完了回来开始写第一章吧 或者先写个大纲,要不然写的章节会 ...
- Python简介及环境安装
Python 官网传送门 Python是一种面向对象的解释性计算机程序设计语言. Python 2.7将于2020年1月1日终止支持,本笔记基于Python3. pip pip 是一个现代的,通用的 ...
- python学习第五章
1.继承 即是一个派生的类(derived class)继承基类(base class)的字段和方法,继承也允许把一个 派生类的对象作为 一个基类 对象对待.通俗来讲就是方便,继承前人的代码,减少工作 ...
- 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性
[源码下载] 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性 作者:w ...