P4137 Rmq Problem / mex(无修改区间最小的未出现过的数)

题目链接:P4137 Rmq Problem / mex

考虑到数字只有n个,那么每次询问的答案肯定在[0,n+1][0,n+1]范围内,所以对于值大于n+1的元素无需考虑。
前缀主席树,每个主席树维护权值最后一次出现的位置,那么对于查询[l,r][l,r]就是查找第r棵树上出现位置小于ll的权值,那么只需要维护最后一次出现位置的最小值即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn=2e5+7;

struct Tree{
    int lc,rc,minn;
}tree[maxn*30];

int root[maxn],tot;
const int inf=0x3f3f3f3f;
int build(int l,int r){
    int k=++tot;
    tree[k].minn=0;
    if(l==r) return k;
    int mid=(l+r)>>1;
    tree[k].lc=build(l,mid);
    tree[k].rc=build(mid+1,r);
    return k;
}

int upd(int p,int l,int r,int id,int val){
    int k=++tot;
    tree[k]=tree[p];
    if(l==r){
        tree[k].minn=val;
        return k;
    }
    int mid=(l+r)>>1;
    if(id<=mid) tree[k].lc=upd(tree[p].lc,l,mid,id,val);
    else tree[k].rc=upd(tree[p].rc,mid+1,r,id,val);
    tree[k].minn=min(tree[tree[k].lc].minn,tree[tree[k].rc].minn);
    return k;
}

int query(int p,int l,int r,int id){
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(tree[tree[p].lc].minn<id) return query(tree[p].lc,l,mid,id);
    return query(tree[p].rc,mid+1,r,id);
}

int main(){
    int n,m,x,l,r;
    scanf("%d%d",&n,&m);
    root[0]=build(0,n+1);
    for(int i=1;i<=n;++i){
        scanf("%d",&x);
        root[i]=root[i-1];
        if(x>n&&x!=n+1) continue;
        root[i]=upd(root[i],0,n+1,x,i);
    }
    while(m--){
        scanf("%d%d",&l,&r);
        printf("%d\n",query(root[r],0,n+1,l));
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章