这是今天学会的内容,RMQ一般用来查询连续区间的信息的比如最大值最小值之类的,巧妙一点的就像本题经过一点转化将统计一个非降序序列的相同子串的最大长度,不过运用RMQ一定要熟练掌握它的预处理以及查询,记熟模版才是关键,看来是有必要每次做题就用个小本记录一下代码。
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100000+5;
const int maxlogn=20;
struct RMQ{
int d[maxn][maxlogn];
void init(const vector<int>&A){
int n=A.size();
for(int i=0; i<n; i++)d[i][0]=A[i];
for(int j=1; (1<<j) <=n; j++)
for(int i=0; i+(1<<j)-1 < n;i++ )
d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int query(int L,int R){
int k=0;
while((1<<(k+1))<=R-L+1)k++;
return max(d[L][k],d[R-(1<<k)+1][k]);
}
};
RMQ rmq;
int main(){
int n,q,l,r,ans;
int left[maxn],right[maxn],a[maxn],num[maxn];
while(1){
scanf("%d",&n);
if(n==0)break;
scanf("%d",&q);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
a[n]=a[n-1]+1;//末尾哨兵处理,化特殊为一般
int start=0;//每一段的起始位置
vector <int> C;
C.clear();
for(int i=0;i<=n;i++)
if(i==0||a[i]>a[i-1]){
if(i>0){
C.push_back(i-start);//将每段末尾下标压入记录
for(int j=start;j<i;j++){//更新前一个区间信息
num[j]=C.size()-1;
left[j]=start;
right[j]=i-1;
}
}
start=i;
}
rmq.init(C);
while(q--){
scanf("%d %d",&l,&r);
l--,r--;
if(num[l]==num[r])ans=r-l+1;
else{
ans=max(right[l]-l+1,r-left[r]+1);
if(num[l]+1<num[r])
ans=max(ans,rmq.query(num[l]+1,num[r]-1));
}
printf("%d\n",ans);
}
}
return 0;
}