P4137 Rmq Problem / mex 强制在线做法
Problem
给定一个数组\(a\),每次询问给定一个区间\([l,r]\),求区间\(\operatorname{mex}\)。
\(n \le 2 \times 10 ^ 5,a_i \le 10 ^ 9\)。
Solution
考虑用主席树做。每个节点记录它代表的区间权值在当前最早出现的位置。查询的时候直接在\(Root_r\)上查询$ < l$的即可。
# include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n,m;
int a[N],Root[N],tot = 0;
struct node
{
int mex,l,r;
}T[N << 5];
void update(int &root,int pre,int l,int r,int x,int d)
{
root = ++tot;
T[root] = T[pre];
if(l == r)
{
T[root].mex = d;
return;
}
int mid = (l + r) >> 1;
if(x <= mid) update(T[root].l,T[pre].l,l,mid,x,d);
if(x > mid) update(T[root].r,T[pre].r,mid + 1,r,x,d);
T[root].mex = min(T[T[root].l].mex,T[T[root].r].mex);
return;
}
int query(int root,int l,int r,int k)
{
if(l == r) return l;
int mid = (l + r) >> 1;
if(T[T[root].l].mex < k) return query(T[root].l,l,mid,k);
else return query(T[root].r,mid + 1,r,k);
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
for(int i = 1; i <= n; i++)
{
if(a[i] >= n) Root[i] = Root[i - 1];
else update(Root[i],Root[i - 1],1,n + 1,a[i] + 1,i);
}
while(m--)
{
int l,r; scanf("%d%d",&l,&r);
printf("%d\n",query(Root[r],1,n + 1,l) - 1);
}
return 0;
}