思路:
last[i]表示上次i出现的位置
p[i]表示这个序列的起始位置
显然长度=i-p[i]+1
然后对于一个区间l~r,把它分为两部分,一部分可以直接求出答案,表明p[i]<l,另一部分要求最大长度
显然二分可以得到
最大值就用ST表
c o d e code code
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int inf=1e6+1;
int last[10001000], p[10001000], a[10001000], f[10001000][30];
int n, m;
int Middle(int l, int r)
{
int m=l, ans=l;
while(l<=r)
{
int mid=l+r>>1;
if(p[mid]<m)
l=mid+1, ans=mid;
else
r=mid-1;
}
return ans;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
last[a[1]+inf]=1, p[1]=1, f[1][0]=1;
for(int i=2; i<=n; i++)
{
p[i]=max(p[i-1], last[a[i]+inf]+1);
f[i][0]=i-p[i]+1;
last[a[i]+inf]=i;
}
for(int j=1; j<=log2(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]);
while(m--)
{
int l, r, now, l1, k=0, maxx=0;
scanf("%d%d", &l, &r);
l++, r++;
now=Middle(l, r);
//cout<<now<<endl;
l1=now+1;
if(l1<=r)
k=log2(r-l1+1), maxx=max(f[l1][k], f[r-(1<<k)+1][k]);
int ans=max(now-l+1, maxx);
printf("%d\n", ans);
}
return 0;
}