https://www.luogu.org/problemnew/show/P1816
今天早上写了三道RMQ的模版题,也算是认识了RMQ是个什么玩意了 - 线段树的简化版本吧下午就要开始公关线段树了,这应该是今天写的最后一道RMQ裸题了吧。
题意:M笔帐,N个问题,就是A1,A2,...,AM这么多的数中求其中一段的最小值。
题目描述
老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记ķ次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3 ...编号,然后不定时的问管家问题,问题是这样的:在一到b号账中最少的一笔是多少为了让管家没时间作假他总是一次问多个问题?
输入输出格式
输入格式:
输入中第一行有两个数M,N表示有m个(m <= 100000)笔账中,n表示有Ñ个问题,N <= 10万。
第二行为米个数,分别是账目的钱数
后面Ñ行分别是Ñ个问题,每行有2个数字说明开始结束的账目编号。
输出格式:
输出文件中为每个问题的答案。具体查看样例。
完整代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
int a[100005];
int dp[100005][30];
int M,N;
void RMQ()
{
for(int i=1; i<=M; i++) dp[i][0]=a[i];
for(int j=1; (1<<j)<=M; j++)
{
for(int i=1; i+(1<<j)-1<=M; i++)
{
dp[i][j]=min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
}
}
int Query_min(int l, int r)
{
int i=0;
while(l-1+(1<<i)<=r) i++;
i--;
return min(dp[l][i], dp[r-(1<<i)+1][i]);
}
int main()
{
while(scanf("%d%d",&M,&N)!=EOF)
{
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
for(int i=1; i<=M; i++)
{
scanf("%d",&a[i]);
}
RMQ();
for(int i=0; i<N; i++)
{
int e1,e2;
scanf("%d%d",&e1,&e2);
if(i==N-1) printf("%d\n",Query_min(e1, e2));
else printf("%d ",Query_min(e1, e2));
}
}
return 0;
}