题意:
n个数,对所有子区间求mex,
把答案组成新的一列数,再求mex。
分析:
先加入数值 (∈[1,i]) 的数,
然后查询是否存在符合条件的区间有i-1个种数。
条件:“两个为i的数之间”或“到a[i]的前缀”
或“从a[i]到结尾”
(有i-1种,说明有连续[1,i-1],mex可能是i,不可能是答案)。
用线段树解决。
t[x]保存的是x最后一次出现的地方,线段树维护区间最小值。
扫到a[i]的时候,设m为[1,a[i]-1]中,出现最早的数所在的位置。
如果m>上一个a[i]出现的位置,
就说明存在两个为a[i]的数之间有a[i]-1个数,mex可以为a[i]。
这样就解决了。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
#define rd(x) scanf("%d",&x);
typedef long long LL;
const int N=1e5+10;
int n,a[N],t[N<<2],las[N],f[N];
void pushup(int rt){ t[rt]=min(t[rt<<1],t[rt<<1|1]); }
int query(int rt,int l,int r,int L,int R){
// cout<<rt<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
if(l>R||r<L) return 1e9;
if(L<=l&&r<=R){
// cout<<rt<<"*"<<t[rt]<<endl;
return t[rt];
}
int mid=l+r>>1;
return min(query(rt<<1,l,mid,L,R),query(rt<<1|1,mid+1,r,L,R));
}
void update(int rt,int l,int r,int x,int val){
// cout<<rt<<"*"<<l<<" "<<r<<" "<<x<<" "<<val<<endl;
if(x<l||x>r) return;
if(l==r) { t[rt]=val; return; }
int mid=l+r>>1;
update(rt<<1,l,mid,x,val);
update(rt<<1|1,mid+1,r,x,val);
pushup(rt);
return;
}
int main(){
rd(n);
rep(i,1,n){
rd(a[i]);
int x=0; if(a[i]!=1) x=query(1,1,n,1,a[i]-1);
// cout<<a[i]<<" "<<x<<endl;
//[1,a[i]-1]中最早出现的数(每次维护的都是每个数最晚出现的地点)晚于于lst[a[i]]
//两个a[i]之间有集齐i-1个
// 存在mex为a[i]的子区间
if(x>las[a[i]]) f[a[i]]=1;
update(1,1,n,a[i],i);las[a[i]]=i;
}
rep(i,2,n+1){
int x=query(1,1,n,1,i-1);
if(x>las[i]) f[i]=1;
}//结尾再统计一次
rep(i,1,n) if(a[i]!=1) f[1]=1;
int i=1;
while(1){
if(f[i]==0){
printf("%d
",i);
return 0;
}
i++;
}
return 0;
}