思路:
这里首先定义几个数组:表示以i结尾的最长完美序列的开头位置,为以2为底i的对数,f数组为每段区间l到r之间的st数组的最大值,上次出现的位置。然后考虑如何更新st数组,首先,明显st数组是单调递增的,也就是大于等于,其次,它肯定大于等于的上一次的出现位置。
考虑L到R这段区间,以R右侧为右端点的我们可以忽略不计(想一想,为什么),L左侧更不用说。因此我们只需要考虑以L到R这段区间为右端点即可。左端点<=L的右端点一定越靠又越好,我们可以二分找出左端点第一个大于等于L的位置x,长度就是x-l+1,之后,左端点在L到R区间内的,我们直接用表维护即可。
代码:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 200007
using namespace std; 
int lg[maxn],st[maxn],pre[maxn*21],f[maxn][21],n,m,p;
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
inline int query(int l, int r) {
  int k=lg[r-l+1];
  return max(f[l][k],f[r-(1<<k)+1][k]);
}
int main() {
  n=qread(),m=qread();
  lg[0]=-1;
  for(int i=1,x;i<=n;++i) {
    x=qread()+maxn*10;
    st[i]=max(st[i-1],pre[x]+1);
    f[i][0]=i-st[i]+1;
    pre[x]=i;
    lg[i]=lg[i>>1]+1;
  }
  for(int j=1;j<=lg[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]);    //st表。
  for(int i=1,l,r;i<=m;++i) {
    l=qread()+1,r=qread()+1;
    if(st[r]<=l) {
      printf("%d\n",r-l+1);
      continue;
    }
    p=lower_bound(st+1,st+1+n,l)-st;      //左端点不在l~r的。 
    int ans=0;
    if(p-1>=l) ans=p-l;                   //p-1-l+1。 
    if(p<=r) ans=max(ans,query(p,r));     //在的,直接st表维护查询即可。 
    printf("%d\n",ans);
  }
  return 0;
}