题意:求一个序列所有连续子序列的mex值的mex
考虑一个数可以成为一段连续子序列的mex,首先没有在子序列里面出现过,且所有小于该数的正整数均在此子序列中出现过。
那么验证一个数$x$是否可以成为mex,整个序列被$x$划分为多个区间,按照权值建一棵线段树维护每个权值出现的最晚位置的最小值。
$1sim n$:当移动到$a[i]$时,看权值为$1sim a[i]-1$的数出现的最晚位置是否都大于$a[i]$上次出现的位置$last[a[i]]$.
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+5; int n,a[maxn],last[maxn]; bool vis[maxn]; struct Node{ int Min; }tree[maxn<<2]; void update(int rt,int l,int r,int pos,int x) { if(l==r) { tree[rt].Min=x; return; } int mid=l+r>>1; if(pos<=mid) update(rt<<1,l,mid,pos,x); else update(rt<<1|1,mid+1,r,pos,x); tree[rt].Min=min(tree[rt<<1].Min,tree[rt<<1|1].Min); } int query(int rt,int l,int r,int L,int R) { if(L<=l&&R>=r) return tree[rt].Min; int mid=l+r>>1,res=0x3f3f3f3f; if(L<=mid) res=query(rt<<1,l,mid,L,R); if(R>mid) res=min(res,query(rt<<1|1,mid+1,r,L,R)); return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); if(a[i]!=1) vis[1]=1; if(a[i]>1&&query(1,1,n,1,a[i]-1)>last[a[i]]) vis[a[i]]=1; last[a[i]]=i; update(1,1,n,a[i],i); } for(int i=2;i<=n+1;++i) if(query(1,1,n,1,i-1)>last[i]) vis[i]=1; int ans=1; while(vis[ans]) ans++; printf("%d ",ans); return 0; }