思路
如何求 mex ?
我们可以在一棵权值线段树(类似桶)上维护
a
i
a_i
ai,最近一次出现的位置的编号插入到权值线段树中,那么从左到右遍历一下权值线段树(桶)第一个没被插的值就是 ans
如何查询区间 ?
考虑 查询区间
[
l
,
r
]
[l,r]
[l,r] 的
m
e
x
mex
mex
为了避免值相同的
a
i
a_i
ai,对权值线段树维护值的影响
我们需要利用主席树来维护插入不同值时的情况
只需查询第
y
y
y 棵树,找到第一个小于
l
l
l 的权值
如何找到第一个小于
l
l
l 的权值 ?
通过维护区间最小值
因为要找到第一
个不存在的自然数
我们首先考虑当前下标的左子树,若左子树的最小值小于 l,那么就说明答案一定在左子树上
否则就去找右子树 (可以依照主席树查询第k小的思想)
Code
const int N = 2e5+10;
int n,m;
struct node{
int l,r,v;
}t[N*40];
int root[200005];
int idx; // 线段树编号
void build(int &o,int pre,int l,int r,int val,int p){
o = ++idx;
t[o] = t[pre];
if( l== r ){
t[o].v = p;
return;
}
int mid = (l+r) >> 1;
if(val <= mid) build(t[o].l,t[pre].l,l,mid,val,p);
else build(t[o].r,t[pre].r,mid+1,r,val,p);
t[o].v = min(t[t[o].l].v,t[t[o].r].v);
}
int ask(int o,int l,int r,int val){
if(l==r) return l;
int mid = (l+r) >> 1;
if(t[t[o].l].v < val) return ask(t[o].l,l,mid,val);
else return ask(t[o].r,mid+1,r,val);
}
int main()
{
_orz;
cin>>n>>m;
vector<int> a(n+1);
forr(i,1,n){
cin >> a[i];
build(root[i],root[i-1],0,1e9,a[i],i);
}
while(m--){
int x,y;
cin>>x>>y;
int ans = ask(root[y],0,1e9,x);
cout << ans << endl;
}
return 0;
}