首页 > 代码库 > 【主席树】Gym - 101237A - MEX-Query

【主席树】Gym - 101237A - MEX-Query

主席树里每个值的位置存当前该值出现的最右位置。

如果root[r]的前缀主席树中,某值最右位置大于等于l,说明该值出现在了l,r中。

所以主席树维护区间最小值,如果左半值域的最小值<l,则说明左半值域有值未在l,r出现,则查询左子树;否则查询右子树。

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 1000010
struct Node{int v,lc,rc;}T[N*22];
int root[N],e;
void Insert(int pre,int cur,int p,int v,int l,int r)
{
    if(l==r)
      {
        T[cur].v=v;
        return;
      }
    int m=(l+r>>1);
    if(p<=m)
      {
        T[cur].lc=++e;
        T[cur].rc=T[pre].rc;
        Insert(T[pre].lc,T[cur].lc,p,v,l,m);
      }
    else
      {
        T[cur].rc=++e;
        T[cur].lc=T[pre].lc;
        Insert(T[pre].rc,T[cur].rc,p,v,m+1,r);
      }
    T[cur].v=min(T[T[cur].lc].v,T[T[cur].rc].v);
}
int Goal;
int Query(int R,int l,int r)
{
    if(l==r) return l;
    int m=(l+r>>1);
    if(T[T[R].lc].v<Goal) return Query(T[R].lc,l,m);
    else return Query(T[R].rc,m+1,r);
}
int n,m,a[N];
int main()
{
    int x,y;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
      {
      	scanf("%d",&x);
        root[i]=++e;
        Insert(root[i-1],root[i],x+1,i,1,1000001);
      }
    scanf("%d",&m);
    for(;m;--m)
      {
        scanf("%d%d",&x,&y);
        Goal=x;
        printf("%d\n",Query(root[y],1,1000001)-1);
      }
    return 0;
}

【主席树】Gym - 101237A - MEX-Query