考慮到數字只有n個,那麼每次詢問的答案肯定在範圍內,所以對於值大於n+1的元素無需考慮。
前綴主席樹,每個主席樹維護權值最後一次出現的位置,那麼對於查詢就是查找第r棵樹上出現位置小於的權值,那麼只需要維護最後一次出現位置的最小值即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
struct Tree{
int lc,rc,minn;
}tree[maxn*30];
int root[maxn],tot;
const int inf=0x3f3f3f3f;
int build(int l,int r){
int k=++tot;
tree[k].minn=0;
if(l==r) return k;
int mid=(l+r)>>1;
tree[k].lc=build(l,mid);
tree[k].rc=build(mid+1,r);
return k;
}
int upd(int p,int l,int r,int id,int val){
int k=++tot;
tree[k]=tree[p];
if(l==r){
tree[k].minn=val;
return k;
}
int mid=(l+r)>>1;
if(id<=mid) tree[k].lc=upd(tree[p].lc,l,mid,id,val);
else tree[k].rc=upd(tree[p].rc,mid+1,r,id,val);
tree[k].minn=min(tree[tree[k].lc].minn,tree[tree[k].rc].minn);
return k;
}
int query(int p,int l,int r,int id){
if(l==r) return l;
int mid=(l+r)>>1;
if(tree[tree[p].lc].minn<id) return query(tree[p].lc,l,mid,id);
return query(tree[p].rc,mid+1,r,id);
}
int main(){
int n,m,x,l,r;
scanf("%d%d",&n,&m);
root[0]=build(0,n+1);
for(int i=1;i<=n;++i){
scanf("%d",&x);
root[i]=root[i-1];
if(x>n&&x!=n+1) continue;
root[i]=upd(root[i],0,n+1,x,i);
}
while(m--){
scanf("%d%d",&l,&r);
printf("%d\n",query(root[r],0,n+1,l));
}
return 0;
}