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;
}
posted @ 2021-08-06 10:06  luyiming123  阅读(40)  评论(0编辑  收藏  举报