不多说,上代码,代码里有详细的思路解释
#include <cstdio>
#include <cstring>
#include <climits>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define pEnter putchar('\n')
#define sc(n) scanf("%d",&(n))
#define pInt(n) printf("%d\n", (n))
#define plInt(n) printf("%lld\n", (n))
#define mem(a,v) memset((a),v,sizeof(a))
#define scc(n, m) scanf("%d%d",&(n), &(m))
#define sccc(n, m, k) scanf("%d%d%d",&(n), &(m), &(k))
#define pVarInt(v) printf("%s = %d\n",#v,(v))
#define rep(var, s, t) for(int var=(s); var<=(t); var++)
#define drep(var, s, t) for(int var=(s); var>=(t); var--)
void PrintArrInt(int arr[], int s, int e){for(int i=s;i<=e;i++){if(i==s)printf("%d",arr[i]);else printf(" %d",arr[i]);}putchar('\n');}
const int maxn = 100000 + 5;
int N, arr[maxn], minv[maxn*4], mex[maxn], las[maxn], maxv;
/*
线段树动态维护区间MEX
题意:给出一个数组,对于其任意一个区间求MEX,再求所有MEX构成的数组的MEX
思路:判断某个数会不会成为某个区间的MEX ->
如果这个数是这个区间的MEX,那么这个区间肯定不包含这个数 ->
假设现在要判断数X,那么对于原数组,如果在两个X之间或在一个X和一个左/右端点之间(总之这个区间是不含X的最大区间),
如果这个区间含有1~X-1的所有数,那么X就是一个MEX ->
现在可以利用las数组在遍历原数组时记录上一个相同的值出现位置,然后判断 las[arr[i]] ~ i 之间是否包含 1~arr[i]-1 ->
!!!!!(这步转化相当重要) 转化为判断 1 ~ arr[i]-1 这些数的在当前的最大索引是否都位于 las[arr[i]] ~ i 之间 ->
转化为 1 ~ arr[i]-1 这些数的最大索引的最小值是否>las[arr[i]] ->
以arr[i]的值为线段树的索引,以索引为线段树的值,支持修改和区间最小查询即可
即:getmin(1, arr[i]-1)>las[arr[i]] 时X为MEX
(注意不要写成树状数组的实现了,因为要修改值)
*/
void update(int o, int L, int R, int pos, int val) {
if(L==R) {minv[o]=val; return;}
int mid=(L+R)>>1;
if(pos<=mid) update(o*2, L, mid, pos, val);
else update(o*2+1, mid+1, R, pos, val);
minv[o]=min(minv[o*2], minv[o*2+1]);
}
int getmin(int o, int L, int R, int lft, int rht) {
if(lft<=L && rht>=R) return minv[o];
int mid=(L+R)>>1;
if(rht<=mid) return getmin(o*2, L, mid, lft, rht);
else if(lft>mid) return getmin(o*2+1, mid+1, R, lft, rht);
else return min(getmin(o*2, L, mid, lft, rht), getmin(o*2+1, mid+1, R, lft, rht));
}
int main() {
sc(N); rep(i, 1, N) sc(arr[i]), maxv=max(maxv, arr[i]);
rep(i, 1, N) {
update(1, 1, maxv, arr[i], i);//每次更新arr[i]位置的索引,使之保持最大
if(arr[i]==1) continue;//注意特判1
int res=getmin(1, 1, maxv, 1, arr[i]-1);
if(res>las[arr[i]]) mex[arr[i]]=1;
las[arr[i]]=i; mex[1]=1;
}
rep(i, 2, maxv+1) {//注意这时las[i] ~ maxv的区间还没有判断
int res=getmin(1, 1, maxv, 1, i-1);
if(res>las[i]) mex[i]=1;
}
int ans = 1;
while(mex[ans]) ans++;
pInt(ans);
return 0;
}