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;
}

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