RMQ算法,求区间最值

 

poj 3264 Balanced Lineup@

 49人阅读 评论(0) 收藏 举报
 分类:
Balanced Lineup
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 45854 Accepted: 21536
Case Time Limit: 2000MS

Description

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers, N and Q
Lines 2..N+1: Line i+1 contains a single integer that is the height of cow i 
Lines N+2..N+Q+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.

Output

Lines 1..Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output

6
3

0

#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int N = 50010; int  minsum[N][20], maxsum[N][20], a[N]; void init(int n); void rmq(int n); int mmax(int l,int r); int mmin(int l,int r);int main() {int n, q;while(scanf("%d %d",&n, &q)!=EOF){for(int i=1;i<=n;i++){scanf("%d", &a[i]);}init(n);rmq(n);while(q--){int l, r;scanf("%d %d", &l, &r);if(l>r){swap(l,r);}int x=mmax(l,r);int y=mmin(l,r);printf("%d\n",x-y);}}return 0; }void init(int n) {for(int i=1;i<=n;i++){minsum[i][0]=a[i];maxsum[i][0]=a[i];}return  ; }void rmq(int n) {int k=int(log(n*1.0)/log(2.0));for(int j=1;j<=k;j++){for(int i=1;i<=n;i++){if(i+(1<<j)-1<=n){minsum[i][j]=min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]);maxsum[i][j]=max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]);}}} }int mmax(int l,int r) {int k=int(log((r-l+1)*1.0)/(log(2.0)));return max(maxsum[l][k],maxsum[r-(1<<k)+1][k]); }int mmin(int l,int r) {int k=int(log((r-l+1)*1.0)/(log(2.0)));return min(minsum[l][k],minsum[r-(1<<k)+1][k]); }

1. 概述

RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值。这两个问题是在实际应用中经常遇到的问题,下面介绍一下解决这两种问题的比较高效的算法。当然,该问题也可以用线段树(也叫区间树)解决,算法复杂度为:O(N)~O(logN),这里我们暂不介绍。

2.RMQ算法

对于该问题,最容易想到的解决方案是遍历,复杂度是O(n)。但当数据量非常大且查询很频繁时,该算法无法在有效的时间内查询出正解。

本节介绍了一种比较高效的在线算法(ST算法)解决这个问题。所谓在线算法,是指用户每输入一个查询便马上处理一个查询。该算法一般用较长的时间做预处理,待信息充足以后便可以用较少的时间回答每个查询。ST(Sparse Table)算法是一个非常有名的在线处理RMQ问题的算法,它可以在O(nlogn)时间内进行预处理,然后在O(1)时间内回答每个查询。

(一)首先是预处理,用动态规划(DP)解决。

设A[i]是要求区间最值的数列,F[i, j]表示从第i个数起连续2^j个数中的最大值。(DP的状态)

例如:

A数列为:3 2 4 5 6 8 1 2 9 7

F[1,0]表示第1个数起,长度为2^0=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的初始值)

这样,DP的状态、初值都已经有了,剩下的就是状态转移方程。

我们把F[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从 i 到i + 2 ^ (j - 1) - 1为一段,i + 2 ^ (j - 1)到i + 2 ^ j - 1为一段(长度都为2 ^ (j - 1))。用上例说明,当i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。F[i,j]就是这两段各自最大值中的最大值。于是我们得到了状态转移方程F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1])。

代码如下:

 

[cpp] view plain copy
  1. void RMQ(int num) //预处理->O(nlogn)  
  2. {  
  3.     for(int j = 1; j < 20; ++j)  
  4.         for(int i = 1; i <= num; ++i)  
  5.             if(i + (1 << j) - 1 <= num)  
  6.             {  
  7.                 maxsum[i][j] = max(maxsum[i][j - 1], maxsum[i + (1 << (j - 1))][j - 1]);  
  8.                 minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 << (j - 1))][j - 1]);  
  9.             }  
  10. }  

这里我们需要注意的是循环的顺序,我们发现外层是j,内层所i,这是为什么呢?可以是i在外,j在内吗?

答案是不可以。因为我们需要理解这个状态转移方程的意义。

状态转移方程的含义是:先更新所有长度为F[i,0]即1个元素,然后通过2个1个元素的最值,获得所有长度为F[i,1]即2个元素的最值,然后再通过2个2个元素的最值,获得所有长度为F[i,2]即4个元素的最值,以此类推更新所有长度的最值。

而如果是i在外,j在内的话,我们更新的顺序就是F[1,0],F[1,1],F[1,2],F[1,3],表示更新从1开始1个元素,2个元素,4个元素,8个元素(A[0],A[1],....A[7])的最值,这里F[1,3] = max(max(A[0],A[1],A[2],A[3]),max(A[4],A[5],A[6],A[7]))的值,但是我们根本没有计算max(A[0],A[1],A[2],A[3])和max(A[4],A[5],A[6],A[7]),所以这样的方法肯定是错误的。

为了避免这样的错误,一定要好好理解这个状态转移方程所代表的含义。

(二)然后是查询。

假如我们需要查询的区间为(i,j),那么我们需要找到覆盖这个闭区间(左边界取i,右边界取j)的最小幂(可以重复,比如查询5,6,7,8,9,我们可以查询5678和6789)。

因为这个区间的长度为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]);

在这里我们也需要注意一个地方,就是<<运算符和+-运算符的优先级。

比如这个表达式:5 - 1 << 2是多少?

答案是:4 * 2 * 2 = 16。所以我们要写成5 - (1 << 2)才是5-1 * 2 * 2 = 1。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/509021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转载】向量空间模型VSM及余弦计算

向量空间模型VSM及余弦计算 向量空间模型的基本思想是把文档简化为以特征项&#xff08;关键词&#xff09;的权重为分量的N维向量表示。 这个模型假设词与词间不相关&#xff08;这个前提造成这个模型无法进行语义相关的判断&#xff0c;向量空间模型的缺点在于关键词之间的…

机器学习入门学习视频和书籍(笔记保存)

我娜姐推荐的资料和我要看的资料记录下&#xff1a; 吴恩达151课时:https://study.163.com/course/courseLearn.htm?courseId1004570029#/learn/video?lessonId1049052745&courseId1004570029机器学习书籍&#xff1a;《Machine Learning in Action》,Peter Harington&a…

【美文保存】nosql数据库对比以及如何巧妙利用redis来提高效率?

1. MySqlMemcached架构的问题 实际MySQL是适合进行海量数据存储的&#xff0c;通过Memcached将热点数据加载到cache&#xff0c;加速访问&#xff0c;很多公司都曾经使用过这样的架构&#xff0c;但随着业务数据量的不断增加&#xff0c;和访问量的持续增长&#xff0c;我们遇…

嵌入式开发——DMA外设到内存

学习目标 加强理解DMA数据传输过程加强掌握DMA的初始化流程掌握DMA数据表查询理解源和目标的配置理解数据传输特点能够动态配置源数据学习内容 需求 uint8_t data; 串口接收(&data);data有数据了 实现串口的数据接收,要求采用dma的方式。 数据交互流程 CPU配置好DMA外…

系统设计类问题

如果让你设计一个秒杀系统&#xff0c;你会如何设计&#xff1f; Redis是一个分布式缓存系统&#xff0c;支持多种数据结构&#xff0c;我们可以利用Redis轻松实现一个强大的秒杀系统。 我们可以采用Redis 最简单的key-value数据结构&#xff0c;用一个原子类型的变量值(Atomic…

B - Ada and Queue

Ada the Ladybug has many things to do. She puts them into her queue. Anyway she is very indecisive, so sometime she uses the top, sometime the back and sometime she decides to reverses it. Input The first line consists of 1 ≤ Q ≤ 106, number of queries…

一种基于邻域的聚类算法

基本概念&#xff1a; 给定数据集D {d1&#xff0c;d2 ,.. &#xff0c;dn}&#xff0c;p和q是D中的两个任意对象。我们使用欧氏距离来评估p和q之间的距离&#xff0c;表示为 dist&#xff08;p&#xff0c;q&#xff09;。 我们将首先给出k-最近邻集合和反向的定义k-最近邻集…

博弈之威佐夫

博弈之威佐夫博弈详解 标签&#xff1a; 数学博弈游戏威佐夫algorithm2014-03-21 10:40 5330人阅读 评论(1) 收藏 举报分类&#xff1a;博弈&#xff08;6&#xff09; 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 威佐夫博弈是博弈中的另一个经…

Maven报错Missing artifact jdk.tools:jdk.tools:jar:1.7

https://blog.csdn.net/u013281331/article/details/40824707

机器学习会议总结1

2017.06.10506实验室会议总结&#xff1a;今天是机器学习第一次正式的开会&#xff0c;即兴奋又慌张&#xff0c;怕自己所学的东西达不到要求。实验室每个人的学习情况及工作情况如下&#xff1a;首先介绍的当然是我们唯有的学长元智&#xff0c;学长元智主要是讲了怎样学习&am…

前缀树和后缀树

Trie树的应用: 除了本文引言处所述的问题能应用Trie树解决之外&#xff0c;Trie树还能解决下述问题&#xff08;节选自此文&#xff1a;海量数据处理面试题集锦与Bit-map详解&#xff09;&#xff1a; 3、有一个1G大小的一个文件&#xff0c;里面每一行是一个词&#xff0c;词的…

学长启蒙

2017.06.20506实验室家才学长课堂总结&#xff1a;第一次正式听家才学长的课堂&#xff0c;课堂主要目的学长凭自己的经验和丰富的知识带领我们入门机器学习&#xff0c;认识机器学习&#xff0c;学习机器学习。 课堂第一项&#xff0c;首先为方便与学长交流&#xff0c;认识&a…

A*算法启发式搜索

最短路径算法&#xff1a; A*算法擅长解决静态路径中最短距离问题&#xff0c;而又不同于Dijkstra算法和Floyd算法&#xff0c;该算法综合了BFS和Dijkstra算法优点&#xff1a;在进行启发式搜索提高算法效率的同时&#xff0c;可以保证找到一条最优路径(基于评估函数&#xff0…

基于维特比算法的概率路径

简介&#xff1a; 维特比算法(Vieterbi algorithm)是一种动态规划算法&#xff0c;探索出很多预测天气的方法&#xff0c;这种基于经验的预测方式&#xff0c;是一种基于历史数据的概率模型。 思想 维特比算法的思想是假设某一个数据的当前状态是依赖于它的前一个状态&#…

Python的Pexpect库

Pexpect 是一个用来启动子程序并对其进行自动控制的纯 Python 模块。 Pexpect 可以用来和像 ssh、ftp、passwd、telnet 等命令行程序进行自动交互。本文主要是针对ssh远程登录&#xff0c;然后执行简单的新建文件夹与拷贝任务Pexpect 的安装&#xff1a;下载&#xff1a;https:…

k-shingles和MinHash优秀文章保存

minhash原理解释&#xff1a;https://www.cnblogs.com/sddai/p/6110704.html k-shingles和minhash使用原理&#xff1a;https://blog.csdn.net/aspirinvagrant/article/details/41281101 代码java实现&#xff1a;https://blog.csdn.net/remoa_dengqinyi/article/details/728…

Python 数据库连接

#!/usr/bin/env python #-*-coding:utf-8-*- #异常处理&#xff0c;with的使用&#xff0c; class Mycontex(object):def __init__(self,name):self.namenamedef __enter__(self):print("__enter__")return selfdef do_self(self):print(do_self)def __exit__(self,e…

中文分词测试语句

研究生命科学研究生命令本科生我从马上下来我马上下来北京大学生喝进口红酒在北京大学生活区喝进口红酒从小学电脑从小学毕业美军中将竟公然说新建地铁中将禁止商业摊点这块地面积还真不小地面积了厚厚的雪让我们以爱心和平等来对待动物阿美首脑会议将讨论巴以和平等问题锌合金…

socket网络编程udp

#!/usr/bin/env python #-*-coding:utf-8-*- #udp socketserver客户端 import socketHOST127.0.0.1 PORT3214 ssocket.socket(socket.AF_INET,socket.SOCK_DGRAM)data你好&#xff01; s.sendto(data.encode(utf-8),(HOST,PORT))while data!bye:datbwhile len(dat)0:dat,addrs.…

几种分类器小结

朴素贝叶斯分类器是假设数据样本特征完全独立&#xff0c;以贝叶斯定理为基础的简单概率分类器。AdaBoost算法的自适应在于前一个分类器产生的错误分类样本会被用来训练下一个分类器&#xff0c;从而提升分类准确率&#xff0c;但是AdaBoost算法对于噪声样本和异常样本比较敏感…