传送门biu~biu~
两道题区别只在于ai的范围,显然>=n的那些ai都是没有意义的,因此两题相同。
权值线段树上的i点记录数字i的最右出现位置,查询区间[l,r]即为查询第r棵线段树上最小的i满足i最右出现的位置
#include<bits/stdc++.h>
#define N 200005
using namespace std;
struct Node{
Node *ch[2];int Min;
Node();
void maintain(){Min=min(ch[0]->Min,ch[1]->Min);}
}*null=new Node,*root[N];
Node::Node():Min(0){
ch[0]=ch[1]=null;
}
inline void init(){
null->ch[0]=null->ch[1]=null;
root[0]=new Node;
}
void build(Node *u,Node *&o,int l,int r,int x,int v){
o=new Node;
if(l==r){
o->Min=v;
return;
}
int mid=l+r>>1;
if(x<=mid){
build(u->ch[0],o->ch[0],l,mid,x,v);
o->ch[1]=u->ch[1];
}
else{
o->ch[0]=u->ch[0];
build(u->ch[1],o->ch[1],mid+1,r,x,v);
}
o->maintain();
}
int Query(Node *o,int l,int r,int v){
if(l==r) return r;
int mid=l+r>>1;
if(o->ch[0]->Min>=v) return Query(o->ch[1],mid+1,r,v);
else return Query(o->ch[0],l,mid,v);
}
int main(){
init();int n,T;
scanf("%d%d",&n,&T);
for(int x,i=1;i<=n;++i){
scanf("%d",&x);
if(x>n) root[i]=root[i-1];
else build(root[i-1],root[i],0,n,x,i);
}
while(T--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",Query(root[r],0,n,l));
}
return 0;
}