题意:给你一个序列,长度为2e5,序列元素的取值范围【-1e6,1e6】。有q次查询,每次查询l,r,问l到r中完美序列的最大值,完美序列的定义是:一段连续的序列满足序列中的数互不相同。
思路:这个居然可以用RMQ,实在是太神奇了。
首先:我用一个a数组记录i位置往前的第一个非法位置,什么意思呢?
序列:1 3 2 5 2 2
a数组:0 0 0 0 3 5
对于第一个位置来说,往前没有非法位置,为0,对于最后一个元素来说,往前第一个非法位置是5.
那么:st【i】【0】的定义就是,以i位置为右端点,往前的完美序列的长度,st【i】【1】就是第 i 位置和第 i+1位置中 分别以他们为右端点的完美序列的长度。
那么,我们怎么利用RMQ来求出答案呢。
分情况:如果,a【r】< l,意味着第 r 个位置往前的第一个非法位置不在询问的区间中,所以,答案就是区间长度。否则,在a数组中找到第一个往前非法位置大于等于 l - 1 的位置记为 p ,那么 p 往后的那些位置的非法位置必定大于等于p,往前的那些位置的非法位置必定小于等于p,那么答案就在 p - l 与 区间【p,r】的st值之中
using namespace std;
const int base = 1e6+10,maxn = 2e5+10;
int pre[base*4+100];
int st[maxn][25],a[maxn];
int solve(int l,int r)
{
int k = log(r-l+1)/log(2);
int ans = max(st[l][k],st[r-(1<<k)+1][k]);
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
int x;
scanf("%d",&x);
x += base;
a[i] = max(a[i-1],pre[x]);
st[i][0] = i - a[i];
pre[x] = i;
}
for(int j = 1; (1<<j) <= n; j++)
for(int i = 1; (i+(1<<j-1)) <= n; i++)
st[i][j] = max(st[i][j-1],st[i+(1<<j-1)][j-1]);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
++l,++r;
if(a[r] < l)
{
printf("%d\n",r-l+1);
continue;
}
int p = lower_bound(a+1,a+1+n,l-1) - a;
int ans = max(p-l,solve(p,r));
printf("%d\n",ans);
}
}