范围最值问题(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. 设计模式 策略模式2 c++11

    根据需求的不同 选择不同的策略算法 之前是保存的各种策略类的指针 这里直接使用 function  bind 选择对应的算法 代码 // 005.cpp: 定义控制台应用程序的入口点. // #inc ...

  2. PHP-预定义函数访问数据库

    (1)复习:自定义函数 (2)调用PHP预定义的函数——访问MySQL数据库 1.函数的基础概念   定义一个简单的函数: function  函数名( ){ #函数主体 }  调用/运行一次函数: ...

  3. merge and saveorupdate

    首先 saveOrUpdate返回void 也就是什么都不返回 而merge会返回一个对象 merge 在执行session.merge(a)代码后,a对象仍然不是持久化状态,a对象仍然不会被关联到S ...

  4. 连续子数组和的最大值plus

    package wodeshiyao; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStre ...

  5. MD5盐值加密

    加密思路 思路解析:(数据解析过程基于16进制来处理的,加密后为16进制字符串) 加密阶段: 对一个字符串进行MD5加密,我们需要使用到MessageDigest(消息摘要对象),需要一个盐值(sal ...

  6. docker学习笔记-安装

    安装docker Ubuntu Docker 安装 Docker 支持以下的 Ubuntu 版本: Ubuntu Precise 12.04 (LTS) Ubuntu Trusty 14.04 (LT ...

  7. springBoot基础

    开始之前最基础的东东here 官网:http://projects.spring.io/spring-boot/ 基础快速构建:http://start.spring.io/ 松哥的博客:http:/ ...

  8. 关于esp32的ADC采集

    对于ADC采集 程序源码如下: /* ADC1 Example This example code is in the Public Domain (or CC0 licensed, at your ...

  9. SOPC与 hello world

    本次设计实验源码位于:http://download.csdn.net/detail/noticeable/9922865 实验目的:通过系统的搭建进一步了解FPGA的SOPC开发流程,并借此了姐pl ...

  10. unigui日志

    unigui日志 uniGUI本身提供了日志功能,利用uniServerModule.ServerLogger来控制如何写日志: Enabled:是否写日志 Options:logIndyExcept ...