• 周六. 8月 20th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

P4137 Rmq Problem / mex 强制在线做法

admin

11月 28, 2021

Problem

给定一个数组(a),每次询问给定一个区间([l,r]),求区间(operatorname{mex})
(n le 2 imes 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
",query(Root[r],1,n + 1,l) - 1);
    }
    return 0;
}

发表回复

您的电子邮箱地址不会被公开。