传送门
本题不好直接求每个子串的
m
e
x
mex
mex,转化一下思路,对于
i
i
i而言,我们不妨检查是否存在一个子串使得
m
e
x
=
i
mex=i
mex=i。
现在讨论满足怎样条件的一个子串 s [ l ∼ r ] s[l\sim r] s[l∼r]的 m e x = i mex=i mex=i:
- s [ l ∼ r ] ≠ i s[l\sim r]\ne i s[l∼r]=i
- 1 , 2 , . . . , i − 1 ∈ s [ l ∼ r ] 1,2,...,i-1\in s[l\sim r] 1,2,...,i−1∈s[l∼r]
于是我们遍历 s s s数组,以当前位置 r + 1 r+1 r+1减去一后的 r r r为右端点,查找一个最远的左端点 l l l使得 s [ l ∼ r ] ≠ s [ r + 1 ] s[l\sim r]\ne s[r+1] s[l∼r]=s[r+1],然后再询问 1 ∼ s [ r + 1 ] − 1 1\sim s[r+1]-1 1∼s[r+1]−1中所有数上一次出现的最远位置 x x x,如果 x < l x<l x<l,那么说明该串 m e x mex mex必不为 s [ r + 1 ] s[r+1] s[r+1],否则必为。
具体实现的话,用 l a s t [ s [ i ] ] last[s[i]] last[s[i]]记录 s [ i ] s[i] s[i]上一次出现的最近位置,用线段树维护 1 ∼ n 1\sim n 1∼n每个数的 l a s t last last值,并能做到查询区间最小值即可。
关于1的话可能要特判,另外答案最大值可能为 n + 2 n+2 n+2,不是 n + 1 n+1 n+1!!
int n,a[maxn],t[maxn<<2],last[maxn],vis[maxn];
void pushup(int rt){
t[rt]=min(t[rt<<1],t[rt<<1|1]);
}
int qry(int rt,int l,int r,int ql,int qr){
if(r<ql || l>qr)return 1e9;
if(ql<=l && r<=qr)return t[rt];
int mid=l+r>>1;
return min(qry(rt<<1,l,mid,ql,qr),qry(rt<<1|1,mid+1,r,ql,qr));
}
void cg(int rt,int l,int r,int x,int val){
if(l==r){
t[rt]=val;
return;
}
int mid=l+r>>1;
if(x<=mid)cg(rt<<1,l,mid,x,val);
else cg(rt<<1|1,mid+1,r,x,val);
pushup(rt);
}
int main(){
int n=rd();
FOR(i,1,n+1){
a[i]=rd();
if(a[i]!=1){
int x=qry(1,1,n,1,a[i]-1);
vis[1]=1;
if(x>last[a[i]])vis[a[i]]=1;
}else vis[2]=1;
cg(1,1,n,a[i],i);
last[a[i]]=i;
}
last[n+1]=0;
FOR(i,2,n+2){
int x=qry(1,1,n,1,i-1);
if(x>last[i])vis[i]=1;
}
FOR(i,1,n+3)if(!vis[i])return wrn(i),0;
}