RMQ入门
注:为方便描述算法 便于记忆 所以ST的代码用Pascal书写 见谅
RMQ,即Range Minimum/Maximum Query问题,给定一个区间,询问不同子区间的最值问题。
当询问次数较少时,朴素算法的时间尚可(暴力做法),k次询问,最坏情况是每次询问最大区间,时间复杂度O(kL),其中k表示询问次数,L表示给定的区间长度。
随着询问次数的增加,朴素算法(应该可以认为是n² 级别的算法)就显得太慢了,因此可以很方便想出线段树做法,节点存储区间最值。那么此时k次查询,L的区间长度,可知时间复杂度为O(k logL);L为定值,则log L为常数,随着k的增大线性增大,相比较朴素算法是大大优化了。
但是还不够。当 n过于大时,即使是线段树也不行。此时考虑ST(Sparse Table)算法。该算法的时间复杂度为两部分:预处理O(L logL),查询则为O(1)。
(关于构造笛卡尔树的方法日后另写qwq)
ST方法的原理类似DP。比如说求[1,100]的最值,如果我能知道[1,64]的最值以及[37,100]的最值,那么总区间的最值,一定是两个分区间中的一个最值。
这个例子很方便理解ST。对于分区间继续拆分,直到出现长度为2的区间;此时长度为2的区间最值就是原序列中两个数的较大值。
运用倍增就可以完成拆分。
于是开始搭建:
begin
init;
readln(m);
to m do
begin
readln(head,tail);
if head>tail then
begin
temp:=head;
head:=tail;
tail:=temp;
end;
writeln(query(head,tail));
end;
end.
init即预处理过程,m为询问的组数。不断读入[head,tail]的待查询区间,给出查询值。
预处理就可以写出来:
procedure init;
var
i:longint;
begin
read(n);
to n do
read(a[i]);
tableLength:=trunc(ln(n)/ln());
createTable(tableLength);
make;
end;
行5-行7就是总区间的读入。之后要打一个2的幂表用以拆分(运用倍增),打出了这个表才可以分区间——例子中的64就是这么算出来的。显然这个表长(也就是最大次数)=logL,写在代码中用换底公式后向下取整,得到表长。
之后以表长建立2的幂表,完成后进入预处理的核心部分make。
建表的code比较简单,不多加赘述。
procedure createTable(k:longint);
var
i:longint;
begin
powerTable[]:=;
powerTable[]:=;
to k do
powerTable[i]:=*powerTable[i-];
end;
预处理核心代码如下:
procedure make;
var
i,j:longint;
begin
to n do
line[i,]:=a[i];
to tableLength do
do
line[j,i]:=max(line[j,i-],line[j+powerTable[i-],i-]);
end;
思想是DP的思想。对于总区间,先两端两端的划分,求其最值;再四段四段分,再八段八段分……line[i,j]表示序列中以i为起点,2的j次为长度的区间的最值。当j==0时自然就退化为当前位置的值。
要注意的是外层循环一定要是次数而不是起点,关于这点可以手动模拟一下感受感受;当外层循环为起点时,line数组求值中的依赖的有半段还未求出,故出错。
查询就比较简单了,由于预处理已经算出了所以可能用到的区间最值,只要做一次拆分,取两分区的max即可。
function query(left,right:longint):longint;
var
t:longint;
begin
t:=trunc(ln(right-left+)/ln());
exit(max(line[left,t],line[right-powerTable[t]+,t]));
end;
完整代码如下(其实只是多了点定义和一个max函数):
var
a:..]of longint;
i,n,m,head,tail,tableLength,temp:longint;
line:..,..]of longint;
powerTable:..]of longint;
function max(a,b:longint):longint;
begin
if a>b then
exit(a)
else
exit(b);
end;
procedure createTable(k:longint);
var
i:longint;
begin
powerTable[]:=;
powerTable[]:=;
to k do
powerTable[i]:=*powerTable[i-];
end;
procedure make;
var
i,j:longint;
begin
to n do
line[i,]:=a[i];
to tableLength do
do
line[j,i]:=max(line[j,i-],line[j+powerTable[i-],i-]);
end;
procedure init;
var
i:longint;
begin
read(n);
to n do
read(a[i]);
tableLength:=trunc(ln(n)/ln());
createTable(tableLength);
make;
end;
function query(left,right:longint):longint;
var
t:longint;
begin
t:=trunc(ln(right-left+)/ln());
exit(max(line[left,t],line[right-powerTable[t]+,t]));
end;
begin
init;
readln(m);
to m do
begin
readln(head,tail);
if head>tail then
begin
temp:=head;
head:=tail;
tail:=temp;
end;
writeln(query(head,tail));
end;
end.
行32的循环上界要控制好,否则会段出错,切记切记。
但是仅仅是ST是不够的。如 P1440 求m区间内的最小值
此题数据规模在m≤n≤2000000内,虽然按理来说不可能但是ST方法会超时。即是加了快读快输也不行。。。
ST超时代码示例:
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
],line[][],a[],n,m;
void createTable(int size){
powerTable[] = ;
; i <= size; ++i){
powerTable[i] = * powerTable[i-];
}
}
void init(){
; i <= n; ++i){
line[i][] = a[i];
}
; i <= floor(log(n)/log()); ++i){
; j <= n-powerTable[i]+; ++j){
line[j][i] = min(line[j][i-],line[j+powerTable[i-]][i-]);
}
}
}
int query(int head,int tail){
)/log());
][c]);
}
int main(int argc, char const *argv[]){
ios::sync_with_stdio(false);
cin >> n >> m;
; i <= n; ++i){
cin >> a[i];
}
cout << << endl;
createTable(floor(log(n)/log()));
init();
; i <= n; ++i){
){
cout << query(,i-) << endl;
}else{
cout << query(i-m,i-) << endl;
}
}
;
}
快读快输部分:
void read(int &x){
x=;char c=getchar();
')c=getchar();
'){
x=x*+c-';
c=getchar();
}
}
void writeln(int x){
,len=;
;len++;}
;putchar(x/y+);x%=y;}
putchar('\n');
}
看来是没救了,试试线段树行不行。。。PS:题解显示是单调队列什么的,没仔细看。
Update:2018 - 06 - 06
找到st的模板题了:https://www.luogu.org/problemnew/show/P3865
用上面的代码改一下就好了,神奇的是cin/cout会超时7个点,改快读快写就A了。。
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
],line[][],a[],n,m;
inline int read(){
,w=;
char ch=getchar();
;ch=getchar();}
+ch-',ch=getchar();
return s*w;
}
inline void write(int x) {
) putchar('-'),x=-x;
) write(x/);
putchar(x%+');
}
void createTable(int size){
powerTable[] = ;
; i <= size; ++i){
powerTable[i] = * powerTable[i-];
}
}
void init(){
; i <= n; ++i){
line[i][] = a[i];
}
; i <= floor(log(n)/log()); ++i){
; j <= n-powerTable[i]+; ++j){
line[j][i] = max(line[j][i-],line[j+powerTable[i-]][i-]);
}
}
}
int query(int head,int tail){
)/log());
][c]);
}
int main(int argc, char const *argv[]){
n = read();
m = read();
; i <= n; ++i){
a[i] = read();
}
createTable(floor(log(n)/log()));
init();
;i <= m;i++){
int a = read(), b = read();
write(query(a, b));printf("\n");
}
;
}
其实大同小异,只改了一部分
RMQ入门的更多相关文章
- RMQ入门解析
参照大佬博客:https://www.cnblogs.com/yoke/p/6949838.html RMQ(Range Minimum/Maximum Query), 是一种问题,即 查询给定区间 ...
- hdu 1754:I Hate It(线段树,入门题,RMQ问题)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- poj 1330(RMQ&LCA入门题)
传送门:Problem 1330 https://www.cnblogs.com/violet-acmer/p/9686774.html 参考资料: http://dongxicheng.org/st ...
- RMQ LAC 入门
RMQ RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大) ...
- RMQ 算法入门
1. 概述 RMQ(Range Minimum/Maximum Query).即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...
- RMQ 的入门 hdu1806
RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干次询问RMQ(i,j),返回数列A中下标在区间[i,j]中的最小/大值 ...
- [转] POJ图论入门
最短路问题此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等)http://acm.pku.edu.cn/JudgeOnline/problem?id=2449题意: ...
- [Luogu P1886]滑动窗口--单调队列入门
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- Java类的继承与多态特性-入门笔记
相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...
随机推荐
- PAT L2-017. 人以群分
题目链接:https://www.patest.cn/contests/gplt/L2-017 题目: 社交网络中我们给每个人定义了一个“活跃度”,现希望根据这个指标把人群分为两大类,即外向型(out ...
- js中三种定义变量 const, var, let 的区别
js中三种定义变量的方式const, var, let的区别 1.const定义的变量不可以修改,而且必须初始化. 1 const b = 2;//正确 2 // const b;//错误,必须初始化 ...
- 【HNOI】五彩斑斓 模拟
[题目描述] 给定一个n*m的矩阵,矩阵的某些位置有一个颜色(可以没有颜色,即为0),现在你可以将矩阵的某一行或者某一列染成同一种颜色,问最少用多少步能达到目标矩阵的染色方案,输出最少步数和方案. [ ...
- JAVA 非对称加密算法RSA
非对称加密算法 RSA过程 : 以甲乙双方为例 1.初始化密钥 构建密钥对,生成公钥.私钥保存到keymap中 KeyPairGenerator ---> KeyPair --> RSAP ...
- 灵活使用ARM汇编的WEAK关键字
//=====================================================================//TITLE:// 灵活使用ARM汇编的WEAK关 ...
- javascript性能
1.js文件放在底部 js文件具有阻塞机制,放在头部,需要等待js下载解析完毕之后才能下载渲染页面,因此需要放在底部
- ctsc&apio2018八日游
day0: 早就知道自己是打酱油的..早就做好了打铁的准备.. Q:那你来干嘛 A:当然是来玩啊!!玩啊!啊!! emmmmm 抱着半期考不及格的卷子瑟瑟发抖地上了飞机. day1:报道!当然还有在宾 ...
- MySQL:Can't create test file XXX.lowe-test
问题说明 今天部署MySQL,在使用mysql_install_db,初始化数据库时报如下错误 180622 11:36:38 mysqld_safe Starting mysqld daemon w ...
- 81.Search in Rotated Sorted Array II---二分变形
题目链接 题目大意:与33题类似,只是这里数组中有重复数值. 法一:解法与33题类似,只是这里要处理1,3,1,1,1这种情况,即有重复值时,mid与left和right都相等时,可以采用right- ...
- 使用IDEA从github中下载fastdfs-client-java
由于在pom文件中加入依赖坐标无法将fastdfs-client-java下载下来,后来通过查资料,发现在中央仓库中没有定义该坐标.为此,使用idea从github下载fastdfs-client-j ...