RMQ总结

RMQ可以用多种算法求解,可以用ST表来实现o(1)的静态求解,也可以用线段树来实现o(logn)的求解,更可以用树状数组实现o(logn*logn)即o(logn^2)的求解。

这里有一道例题,运用二分+RMQ求解,因为是静态的所以可以用ST表快速求解。

【GDOI2005】河床 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536
KB Detailed Limits

Description
  地理学家们经常要对一段河流进行测量分析。他们从上游开始向下游方向等距离地选择n(<=30000)个点测量水位深度。得到一组数据d1,d2,…,dn,回到实验室后数据分析员根据需要对数据进行分析,发掘隐藏在数据背后的规律。最近,乌龙博士发现某种水文现象与河床地势有关,于是他指示他手下的分析员要找出一段河流中最大高低起伏差不超过k(k<=100)的最长一段。这看似一个复杂的问题,由于任务紧急,分析员来求助于你,并告诉你博士的所有数据都精确到个位。

Input
  输入文件有两行:第一行是整数n,k,分别表示测量点的个数和博士要求的最大水深差(也就是河床地势差)。第二行有n个整数,表示从上游开始依次得到的水位深度
di(1<=i<=n,0<=di<=32767)。

Output   输出文件只有一行,是整数m,表示最长一段起伏不超过k的河流长度,用测量点个数表示。

Sample Input 6 2 5 3 2 2 4 5

Sample Output 4

Data Constraint

Hint   提示:从第二个测量点到第五个测量点之间的那段:3 2 2 4,他们起伏最大时4-2=2。

#include<bits/stdc++.h>
using namespace std;
int n,k,i,j,d[31111],gax[31111],dp[31111],gin[31111],dpback[31111],ans,fx[111111][21],fn[111111][21];
int rmqx(int x,int y)
{
	int z=(int)(log(y-x+1)/log(2));
	return max(fx[x][z],fx[y-(1<<z)+1][z]);
}
int rmqn(int x,int y)
{
	int z=(int)(log(y-x+1)/log(2));
	return min(fn[x][z],fn[y-(1<<z)+1][z]);
}
bool check(int xx,int yy)
{
	int maxn=rmqx(xx,yy),minn=rmqn(xx,yy);
	if(maxn-minn<=k) return true;
	else return false;
}
int main()
{
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&d[i]);
		fx[i][0]=fn[i][0]=d[i];
	}
	ans=0;
	for(j=1;1<<j<=n;j++)
		for(i=1;i+(1<<j)-1<=n;i++)
			fx[i][j]=max(fx[i][j-1],fx[i+(1<<j-1)][j-1]);
	for(j=1;1<<j<=n;j++)
		for(i=1;i+(1<<j)-1<=n;i++)
			fn[i][j]=min(fn[i][j-1],fn[i+(1<<j-1)][j-1]);
	for(i=1;i<=n;i++)
	{
		int l=i,r=n,mid;
		while(l<r)
		{
			if(r-l==1)
			{
				if(check(i,r))
				{
					l=r;
					break;
				}
				else
				{
					r=l;
					break;
				}
			}
			mid=(l+r)/2;
			if(check(i,mid))
			{
				l=mid;
			}
			else
			{
				r=mid-1;
			}
		}
		if(ans<l-i+1) ans=l-i+1;
	}
	printf("%d\n",ans);
}
上一篇:关于com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure的解决


下一篇:C++ ST表