RMQ区间最值查询
RMQ区间最值查询
概述
RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,
回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值。这两个问题是在实际应用中经
常遇到的问题,下面介绍一下解决这两种问题的比较高效的算法。
分析:
对于该问题,最容易想到的解决方案是遍历,复杂度是O(n)。但当数据量非常大且查询很频繁时,该算法无法
在有效的时间内查询出正解。
这里介绍Tarjan的Sparse-Table算法,预处理时间为O(nlogn),但查询只需要O(1),并且常数很小,算法也很容易写出。
预处理
设A[i]是要求区间最值的数列,F[i, j] 表示从第 i 个数起连续 2j 个数中的最大值。(DP的状态)
例如 A 数列为:3 2 4 5 6 8 1 2 9 7
F[1,0]表示第1个数起,长度为20=1的最大值,其实就是3这个数。
同理 F[1,1] = max(3,2) = 3, F[1,2]=max(3,2,4,5) = 5,F[1,3] = max(3,2,4,5,6,8,1,2) = 8;
首先:F[i,0]就等于A[i]。(DP的初始值)
其次:我们把F[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从 i 到i + 2 (j - 1) - 1为一段,i + 2 (j - 1) 到 i + 2 j - 1为一段
于是我们得到了
状态转移方程 F[i, j]=max(F[i,j-1], F[i + 2(j-1),j-1])。
void RMQ_init(const vector<int> &A) {
int n = A.size();
for(int i = 0; i < n; ++i) d[i][0] = A[i];
for(int j = 1; (1 << j) <= n; ++j)
for(int i = 0; i + (1 << j) - 1 < n; ++i)
d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
}
查询:
假如我们需要查询的区间为(i,j),那么我们需要找到覆盖这个闭区间(左边界取i,右边界取j)的最小幂
因为这个区间的长度为 j - i + 1,所以我们可以取 k=log2( j - i + 1) ,则有:RMQ(A, i, j)=max{ F[i , k] , F[ j - 2 k + 1, k] }。
举例说明,要求区间[2,8]的最大值,k = log2(8 - 2 + 1)= 2,即求max(F[2, 2],F[8 - 2 2 + 1, 2]) = max(F[2, 2],F[5, 2]);
int RMQ(int L, int R) {
int k = 0;
while((1 << (k + 1)) <= R - L + 1) ++k;
return max(d[L][k], d[R - (1 << k) + 1][k]);
}
例题:
题目描述
老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,
由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。
于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,
问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。
输入格式:
输入中第一行有两个数m,n表示有m(m<=100000)笔账,n表示有n个问题,n<=100000。
第二行为m个数,分别是账目的钱数
后面n行分别是n个问题,每行有2个数字说明开始结束的账目编号。
输出格式:
输出文件中为每个问题的答案。具体查看样例。
输入输出样例
输入样例#1:
10 3
1 2 3 4 5 6 7 8 9 10
2 7
3 9
1 10
输出样例#1:
2 3 1
代码:
#include<iostream>
#include<bits/stdc++.h>
using namespace std; int dp[500100][20];//dp[i][j]是从第i个数起,到第2^j个数止的,最小值
int main(){
int n,q;
cin>>n>>q;
int *arr = new int[n+1];
for (int i = 1; i <= n; i++){
cin>>arr[i];
} for (int i = 1; i <= n; i++) dp[i][0]=arr[i];
int count=0;
while((1<<count)<=n)count++;
// cout<<"count="<<count<<" "<<endl;
for(int j=1;j<=count;j++)
for(int i=1;i<=n;i++)
dp[i][j]=min(dp[i][j-1],dp[i+ (1<< (j-1) ) ][j-1]);
int L,R,k;
while (q--){
cin>>L>>R;
k=0;
while (1<<(k+1)<=R-L+1)k++;
cout<<min(dp[L][k],dp[R-(1<<k)+1][k])<<" ";
}
}
RMQ区间最值查询的更多相关文章
- 【RMQ】 区间最值查询详解
1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...
- HDU 1754 I Hate It(线段树之单点更新 区间最值查询)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- POJ 3264:Balanced Lineup(区间最值查询ST表&线段树)
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 75294 Accepted: 344 ...
- hdu1754 I hate it线段树模板 区间最值查询
题目链接:这道题是线段树,树状数组最基础的问题 两种分类方式:按照更新对象和查询对象 单点更新,区间查询; 区间更新,单点查询; 按照整体维护的对象: 维护前缀和; 维护区间最值. 线段树模板代码 # ...
- NBOJv2 1004 蛤玮打扫教室(线段树区间更新区间最值查询)
Problem 1004: 蛤玮打扫教室 Time Limits: 1000 MS Memory Limits: 65536 KB 64-bit interger IO format: %l ...
- HDU 1754 I Hate It(线段树单点更新区间最值查询)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- RMQ(区间最值问题)
问题: RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大) ...
- nyoj 119士兵杀敌(三)(线段树区间最值查询,RMQ算法)
题目119 题目信息 执行结果 本题排行 讨论区 士兵杀敌(三) 时间限制:2000 ms | 内存限制:65535 KB 难度:5 描写叙述 南将军统率着N个士兵,士兵分别编号为1~N,南将军常 ...
- RMQ 区间最大值 最小值查询
/*RMQ 更新最小值操作 By:draymonder*/ #include <iostream> #include <cstdio> using namespace std; ...
随机推荐
- 复杂字符串转List<JSONObject>
public static List<JSONObject> getlist(String data){ ObjectMapper mapper = new ObjectMapper(); ...
- 如何远程调试自定义开发的Flume应用
一.前言 Flume作为当下最流行的大数据采集组件之一.其本身拥有分布式/高可靠/高可用等优点,但相比较于Flink/Spark/Kafka等大数据组件,其对于本地调试的功能支持度并不高,如果我们没有 ...
- 保存Total Commander的列宽
Total Commander的默认列宽经常显示不全内容,需要手工调整,用"Menu -> Configuration -> Save Position"可以永久保存列 ...
- JVM-初见
目录 JVM的体系结构 类加载器 双亲委派机制 Native PC程序计数器 方法区(Method Area) 栈 堆 调优工具 常见JVM调优参数 常见垃圾回收算法 引用计数算法 复制算法 标记-清 ...
- Oracle 数据库的导入与导出
1.导入 打开cmd,用管理员登录:sqlplussys as sysdba密码不用输: 创建表空间:create tablespace tablespaceName datafile 'E:\tab ...
- Xilinx约束学习笔记(二)—— 定义时钟
2. 定义时钟 2.1 关于时钟 为了获得最佳精度路径覆盖信息,必须正确定义时钟. 时钟要定义在时钟树的根 pin 或 port 上,称为 source point. 时钟的边缘应该由周期和波形进行组 ...
- SpringBoot集成<个推推送> Maven 下载jar包异常处理本地打包下载
问题描述 公司需要对用户进行消息推送,选择了个推,由于是Java进行开发,个推操作文档, 这是官网上安装的方式,可是不成功,无论怎么样都无法把Jar包下载下来! MAVEN方式(本人测试Jar无法下载 ...
- 深入浅出Mybatis系列(一)---Mybatis简介
1.什么是MyBatis? MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且 ...
- 大数据学习之 LINUX
##大数据学习 古斌6.6 01. linux系统的搭建: 选用 Contos 6.5 x64位系统 (CentOS-6.5-x86_64-minimal.iso) 我选择的为迷你版 模板机: bla ...
- JDBC中级篇(MYSQL)——在JDBC中如何获得表中的,自增长的字段值
注意:其中的JdbcUtil是我自定义的连接工具类:代码例子链接: package c_increment; import java.sql.Connection; import java.sql.P ...