RMQ学习总结(附带简单例题)
来源:互联网 发布:日本等级观念知乎 编辑:程序博客网 时间:2024/06/16 02:30
RMQ (Range Minimum/Maximum Query)问题
含义:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。
时间复杂度:预处理时间复杂度O(n*log(n)),查询O(1)
基础:dp
F[i][j]表示从第i位起,2^j个数中的最值。
那么dp的初值是什么?
显然f[i][0]的值为a[i]。
Dp的方程呢?
对于i~i+2^j-1这段区间,我们将它分为长度相同的两部分:
显然2^j=2^(j-1)+2^(j-1),所以分为i~i+2^(j-1)-1, i+2^(j-1)~i+2^j-1;
那么f[i][j]=max/min(f[i][j-1],f[i+2^(j-1)][j-1])。
所以当查询一段区间[l,r]时:
Int k=trunc(log2(r-l+1));
Int ans=max/min(f[l][k],f[r-2^k+1][k]);
有三道例题热身:
#1巴蜀oj1939
Description
现给你n(<=1000000)个整数(都小于longint),有k(0< k<= 1000000)个询问,对于每个询问(L,R),回答(L,R)内的最大值为多少?
Input
第一行两个整数n和k;第二行为n个整数,第三行到第k+2行为k个询问;
Output
共k行,每行为一个询问的最大值
Sample Input
10 2
3 2 4 5 6 8 1 2 9 7
1 8
2 9
3 2 4 5 6 8 1 2 9 7
1 8
2 9
Sample Output
8
9
9
显然这是一道非常裸的rmq问题,只需维护max即可。
#include<iostream>#include<cstdio>#include<cmath>using namespace std;int n,k,a[1000005];int f[1000005][25]; void rmq_prepare(){for(int i=1;i<=n;i++) f[i][0]=a[i];for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++)f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);}int query(int l,int r){int k=trunc(log2(r-l+1));return max(f[l][k],f[r-(1<<k)+1][k]);}int main(){scanf("%d%d",&n,&k);for(int i=1;i<=n;i++) scanf("%d",&a[i]);rmq_prepare();int l,r;for(int i=1;i<=k;i++){scanf("%d%d",&l,&r);printf("%d\n",query(l,r));}return 0;}
#2 poj3264
Description
在每天挤奶的时候,农民约翰的N头牛(1≤n≤50000)总是排成一列。有一天,约翰决定与他的牛们一起玩一个极限飞盘游戏。为了简单起见,他将从奶牛队列里面选一定范围内的奶牛来玩这个游戏。然而所有的牛对这个游戏都很感兴趣。农民约翰列出了Q份名单(1≤Q≤200000)和每个奶牛的高度(1≤高度≤1000000)。对于每一份名单,他想你帮助他确定在每份名单中高度最高的奶牛与高度最低的奶牛的高度差是多少。
Input
第一行为N(1≤N≤50000)和Q(1≤Q≤200000);从第2行到第N+1行,每行一个数字,表示第i头牛的高度(1≤height≤1000000);从第N+2行到第N+Q+1行,每行两个整数A和B(1≤A≤B≤N),表示从第A头牛到第B头牛的范围。
Output
从第一行到第Q行,每行一个整数,表示从第A头牛到第B头牛之间,最高牛与最矮牛的高度差。
Sample Input
6 3
1
7
3
4
2
5
1 5
4 6
2 2
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output
6
3
0
3
0
这也是一道比较裸的rmq问题,只需维护每段区间的最大最小即可。
#include<iostream>#include<cstdio>#include<cmath>using namespace std;int n,m,a[50005];int fmi[50005][20];int f[50005][20];void st_prepare(){for(int i=1;i<=n;i++)fmi[i][0]=a[i],f[i][0]=a[i];for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) fmi[i][j]=min(fmi[i][j-1],fmi[i+(1<<(j-1))][j-1]), f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);}int query(int l,int r){int k=trunc(log2(r-l+1));return (max(f[l][k],f[r-(1<<k)+1][k])-min(fmi[l][k],fmi[r-(1<<k)+1][k]));}int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);st_prepare();int l,r;for(int i=1;i<=m;i++){scanf("%d%d",&l,&r);printf("%d\n",query(l,r));}return 0;}
#3 poj3368
Description
给你一个含有n个整数的非递减序列a1 , a2 , ... , an,要求你回答一系列的询问,如i和j (1 ≤ i ≤ j ≤ n),回答出ai , ... , aj之间出现频率最多数字为多少次?
Input
输入文件包含多组数据,每组数据的第1行包含两个整数n和q(1 ≤ n, q ≤ 100000),第2行为n个用空格分开的整数a1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}),接下来的q行,每行包含两个整数i和j。文件以0作为结束标记。
Output
对于每一个询问输出一行,为在此区间内出现频率最多数字为多少次?
Sample Input
10 3
1
4
3
4
3
Hint
【数据范围】
对于30的数据,1≤n,q≤1000;
对于100的数据,1≤n,q≤1000000;
对于30的数据,1≤n,q≤1000;
对于100的数据,1≤n,q≤1000000;
这道终于不太裸了。。。
f数组表示是连续的相同数块中的第几位。
例如:题目中的数据
a:-1 -1 1 1 1 1 3 10 10 10
f:1 2 1 2 3 4 1 1 2 3
对于每个询问[l,r]
首先找到在序列中和a[l]值相同且连续的最大位置,即下面代码中的t。
那么对于[t,r]这段区间中,f[i]的最大值就是频率最大的数的频率。
用rmq处理最大值。
再用它与(t-l)比较,更新答案。
下面贴出代码:
#include<iostream>#include<cstdio>#include<cmath>#include<cstring>using namespace std;int n,q;int m[100005][20];int f[100005];int a[100005];void st_prepare(){for(int i=1;i<=n;i++)m[i][0]=f[i];for(int j=1;(1<<j)<=n;j++) for(int i=1;i-1+(1<<j)<=n;i++) m[i][j]=max(m[i][j-1],m[i+(1<<(j-1))][j-1]);}int rmq(int l,int r){if(l>r)return 0;int k=trunc(log2(r-l+1));return max(m[l][k],m[r-(1<<k)+1][k]);}int main(){ while(scanf("%d",&n)&&n) { scanf("%d",&q); memset(a,0,sizeof(a)); a[0]=1005; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]==a[i-1]) f[i]=f[i-1]+1; else f[i]=1; } st_prepare(); for(int i=1;i<=n;i++)cout<<f[i]<<endl; int l,r; for(int i=1;i<=q;i++) { scanf("%d%d",&l,&r); int t=l; while(t<=r&&a[t]==a[t-1]) t++; printf("%d\n",max(rmq(t,r),t-l)); } } return 0;}
0 1
- RMQ学习总结(附带简单例题)
- 巴蜀oj1939(RMQ 的例题 )
- java 基础学习总结(附带eclipse一些常用操作)
- 初涉莫比乌斯反演(附带例题)
- java中4种循环方法(附带例题)
- JSP-Session简单总结-附带小案例
- LCA三种算法学习(离线算法tarjan+在线算法转rmq+在线倍增)例题poj1330、1470;hdu4547、2874
- NYOJ 119 士兵杀敌(三)[RMQ例题]【解题报告】
- 第三章例题8 (频繁出现的数值)RMQ
- RMQ ST算法 uva11235(蓝书例题)
- RMQ 之 ST算法的使用 【总结】 【附带求固定区间长度的一维技巧】
- RMQ小讲 【 理解 + 例题 】
- RMQ算法初学的学习总结
- 简单RMQ
- 2017图灵杯问题E 简单的RMQ(RMQ)
- RMQ 总结
- RMQ总结
- AsyncTask总结(经典,附带源码)
- 2015 Multi-University Training Contest 6
- ConcurrentHashMap代码片段
- SSL VPN
- 事务特性
- iOS NSDateFormatter格式详细列表一览
- RMQ学习总结(附带简单例题)
- Linux - script练习
- 分书问题
- libgtk-x11-2.0.so.0
- OpenFLow协议学习笔记-(1)概述
- QTP录制WEB脚本空白
- LinkedList实现基于LRU算法的缓存
- 让shell脚本在后台飞
- The type SmsManager is deprecated错误解决