维护每一个权值最后一次出现的位置,当l->内小于x的权值最后一次均出现在l左侧x可行,然后树上二分,因为要储存历史版本,所以用主席树。
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 200021
using namespace std;
int n,ls[maxn*34],rs[maxn*34],rt[maxn],tot,Min[maxn*34],m;
void insert(int x,int& y,int l,int r,int id,int val){
y=++tot;ls[y]=ls[x],rs[y]=rs[x];
if(l==r){Min[y]=val;return;}
int mid=l+r>>1;
if(id>mid)insert(rs[x],rs[y],mid+1,r,id,val);
else insert(ls[x],ls[y],l,mid,id,val);
Min[y]=min(Min[ls[y]],Min[rs[y]]);
}
int query(int x,int l,int r,int v){
if(l==r)return l;
int mid=l+r>>1;
if(Min[ls[x]]>=v)return query(rs[x],mid+1,r,v);
else return query(ls[x],l,mid,v);
}
int main(){
scanf("%d%d",&n,&m);
for(int x,i=1;i<=n;i++){
scanf("%d",&x);if(x>n){rt[i]=rt[i-1];continue;}
insert(rt[i-1],rt[i],1,n+1,x+1,i);
}int a,b;
while(m--){
scanf("%d%d",&a,&b);
printf("%d\n",query(rt[b],1,n+1,a)-1);
}return 0;
}