poj2452 Sticks Problem RMQ问题
题目大意说:给出一系列的木棒的长度,求出一个最大的区间[x,y],满足所有的len[k]>len[i] && len[k]<len[j] ,i<=k<=j。我看的题目分类说这个题目用RMQ,所有就用了RMQ实现,由于开始的时候我是枚举的所有的区间,所以肯定超时,后来改为从i找出以i开始的最大区间范围,然后在这个范围内求出最大值的下标j,那么j就是从i开始的所有>i且<j的最大区间,枚举采用二分,这样时间复杂度为O(nlogn).
#include <iostream>
#include <stdio.h>
#include <cmath>
const int N=50001;
using namespace std;
int m[N],large[N][17],smal[N][17];
inline int get_max(int a,int b)
{
return a>b?a:b;
}
inline int get_min(int a,int b)
{
return a<b?a:b;
}
void initrmq(int n)
{
int i,j;
for(i=0;i<n;i++)
{
large[i][0]=i;
smal[i][0]=i;
}
for(j=1;(1<<j)<=n;j++)
{
for(i=0;i+(1<<j)-1 < n;i++)
{
if(m[large[i][j-1]] > m[large[i+(1<<(j-1))][j-1]])
large[i][j]=large[i][j-1];
else
large[i][j]=large[i+(1<<(j-1))][j-1];
if(m[smal[i][j-1]] < m[smal[i+(1<<(j-1))][j-1]])
smal[i][j]=smal[i][j-1];
else
smal[i][j]=smal[i+(1<<(j-1))][j-1];
}
}
}
int querymin(int i,int j)
{
int k=(int)(log(1.0*(j-i+1))/log(2.0));
if(m[smal[i][k]] < m[smal[j-(1<<k)+1][k]])
return smal[i][k];
return smal[j-(1<<k)+1][k];
}
int querymax(int i,int j)
{
if(i>j)
{
int tmp=i;
i=j;
j=tmp;
}
int k=(int)(log(1.0*(j-i+1))/log(2.0));
if(m[large[i][k]] > m[large[j-(1<<k)+1][k]])
return large[i][k];
return large[j-(1<<k)+1][k];
}
//找出以i开头的最大区间范围
int findIdx(int n,int l)
{
int mid,i=l,j=n-1;
while(i+1<=j)
{
mid=(i+j)>>1;
if(querymin(l,mid) == l)//如果现在的区间最小值下标是l,则扩大范围,否则缩小范围
i=mid+1;
else
j=mid-1;
}
return j;
}
int solve(int n)
{
int i,j,ans=0,k,l,r;
l=0;
r=n-1;
for(i=0;i<n-1;i++)
{
j=findIdx(n,i);
k=querymax(i,j);
// cout<<j<<" "<<k<<endl;
if(k-i > ans)
ans=k-i;
}
if(ans)
return ans;
return -1;
}
int main()
{
int i,n;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
scanf("%d",&m[i]);
memset(large,0,sizeof(large));
memset(smal,0,sizeof(smal));
initrmq(n);
int ans=solve(n);
printf("%d\n",ans);
}
return 0;
}