范围最值问题(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算法)的更多相关文章

  1. RMQ(ST(Sparse Table))(转载)

    1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...

  2. codeforce 359D 二分+ 动态规划(sparse table)

    原题链接:http://codeforces.com/problemset/problem/359/D 思路:首先对符合题目的长度(r-l)从0到n-1进行二分查找,对每一个长度进行check,看是否 ...

  3. RMQ ---- ST(Sparse Table)算法

    [概述]      RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返 ...

  4. 51NOD1174 区间最大数 && RMQ问题(ST算法)

    RMQ问题(区间最值问题Range Minimum/Maximum Query) ST算法 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度 ...

  5. 一维二维Sparse Table

    写在前面: 记录了个人的学习过程,同时方便复习 Sparse Table 有些情况,需要反复读取某个指定范围内的值而不需要修改 逐个判断区间内的每个值显然太浪费时间 我们希望用空间换取时间 ST表就是 ...

  6. RMQ问题之ST算法

    RMQ问题之ST算法 RMQ(Range Minimum/Maximum Query)问题,即区间最值问题.给你n个数,a1 , a2 , a3 , ... ,an,求出区间 [ l , r ]的最大 ...

  7. poj 3264 区间最大最小值 RMQ问题之Sparse_Table算法

    Balanced Lineup Time Limit: 5000 MS Memory Limit: 0 KB 64-bit integer IO format: %I64d , %I64u Java ...

  8. 基于稀疏表(Sparse Table)的RMQ(区间最值问题)

    在RMQ的其他实现方法中,有一种叫做ST的算法比较常见. [构建] dp[i][j]表示的是从i起连续的2j个数xi,xi+1,xi+2,...xi+2j-1( 区间为[i,i+2j-1] )的最值. ...

  9. ST (Sparse Table:稀疏表)算法

    1541:[例 1]数列区间最大值 时间限制: 1000 ms         内存限制: 524288 KB提交数: 600     通过数: 207 [题目描述] 输入一串数字,给你 MM 个询问 ...

  10. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

随机推荐

  1. leveldb 学习记录(六)SSTable:Block操作

    block结构示意图 sstable中Block 头文件如下: class Block { public: // Initialize the block with the specified con ...

  2. Linux配置ntp时间服务器(全)

    时间服务器作用: 大数据产生与处理系统是各种计算设备集群的,计算设备将统一.同步的标准时间用于记录各种事件发生时序, 如E-MAIL信息.文件创建和访问时间.数据库处理时间等. 大数据系统内不同计算设 ...

  3. SQLite3命令操作大全

    SQLite3命令操作大全 SQLite库包含一个名字叫做sqlite3的命令行,它可以让用户手工输入并执行面向SQLite数据库的SQL命令.本文档提供一个样使用sqlite3的简要说明. 一.ql ...

  4. bgfx入门练习1——切换图形API驱动模式DX与OpenGL

    翻了下上次编译bgfx是去年2月份的事了,最近正好想试试DX,OpenGL双驱动,看Urho3D和Klayge光封装就头痛,人又懒,写OpenGL时也基本glfw,于是想到bgfx,不如再试试. 发现 ...

  5. 让IE8支持html5中的video标签

    这是一篇综合几个前辈的解决方案. 使用video的时候,要遇到的问题. ①不兼容ie9及其以下版本 在<head>里添加两行, 参考张鑫旭前辈的博客,但是在ie8中薄播放. <!-- ...

  6. Html5与Css3知识点拾遗(四)

    web图像 JPEG:适用于大多数照片,颜色较多,可接受质量损失的图像 PNG-8:适用标识.重复的图案以及其他颜色较少的图像或具有连续颜色的图像 PNG-24:不支持颜色更多的图像,适用与颜色丰富且 ...

  7. 【python接口自动化测试教程】00---00章节就代表开篇吧

    今天突然想写个接口测试教程,由于本人是初级的比小白稍微好那么一丢丢,所以不知道能不能坚持下来 写的不对的地方还请大咖指教 先去忙自己的工作了,忙完了回来开始写第一章吧 或者先写个大纲,要不然写的章节会 ...

  8. Python简介及环境安装

    Python 官网传送门 Python是一种面向对象的解释性计算机程序设计语言. Python 2.7将于2020年1月1日终止支持,本笔记基于Python3. pip pip 是一个现代的,通用的 ...

  9. python学习第五章

    1.继承 即是一个派生的类(derived class)继承基类(base class)的字段和方法,继承也允许把一个 派生类的对象作为 一个基类 对象对待.通俗来讲就是方便,继承前人的代码,减少工作 ...

  10. 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性

    [源码下载] 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性 作者:w ...