首先可以在O(n)的时间内求出1~i(for i 1~n)的答案ans[ i ]。然后对于l~r的答案与l+1~r答案的关系,把i~nxt[ i ]-1的所有大于a[i]的ans都改为a[i]就可以了,nxt[ i ]表示下一个最近的 值也是a[i]的位置。询问排一下序。
#include<cstdio>
#include<iostream>
#include<algorithm>
#define maxn 200005
using namespace std;
void read(int &a)
{
a=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')
{
a*=10;a+=c-'0';
c=getchar();
}
}
struct Que{
int l,r;
int id,ans;
}q[maxn];
bool cmp(Que A,Que B)
{return A.l<B.l;}
bool cmp2(Que A,Que B)
{return A.id<B.id;}
int a[maxn];
bool use[maxn];
int ans[maxn];
struct XDS{
struct xds
{
int l,r;
int add;
}tree[maxn<<2];
void build(int x,int l,int r)
{
tree[x].l=l;
tree[x].r=r;
tree[x].add=maxn;
if(l==r) return ;
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
void spread(int x)
{
tree[x<<1].add=min(tree[x].add,tree[x<<1].add);
tree[x<<1|1].add=min(tree[x].add,tree[x<<1|1].add);
}
int L,R;
void change(int x,int d)
{
if(tree[x].l>=L&&tree[x].r<=R)
{
tree[x].add=min(tree[x].add,d);
return ;
}
spread(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(mid>=L) change(x<<1,d);
if(mid<R) change(x<<1|1,d);
}
int ask(int x)
{
if(tree[x].l==L&&tree[x].r==R)
return min(ans[L],tree[x].add);
spread(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(mid>=L) return ask(x<<1);
return ask(x<<1|1);
}
}TR;
int fst[maxn],nxt[maxn];
int main()
{
int n,m,Max=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
read(a[i]);
Max=max(Max,a[i]);
}
for(int i=0;i<=Max;i++)
fst[i]=n+1;
for(int i=n;i>=1;i--)
{
nxt[i]=fst[a[i]];
fst[a[i]]=i;
}
for(int i=1;i<=n;i++)
{
use[a[i]]=1;
int A=ans[i-1];
while(use[A]) A++;
ans[i]=A;
}
for(int i=1;i<=m;i++)
{
read(q[i].l);
read(q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
TR.build(1,1,n);
int H=1;
for(int i=1;i<=n;i++)
{
while(q[H].l==i)
{
TR.R=TR.L=q[H].r;
q[H].ans=TR.ask(1);
H++;
}
TR.L=i,TR.R=nxt[i]-1;
TR.change(1,a[i]);
}
sort(q+1,q+m+1,cmp2);
for(int i=1;i<=m;i++)
printf("%d\n",q[i].ans);
return 0;
}