题目链接:https://codeforces.ml/contest/1436/problem/E
题目大意
给定一个序列,每次枚举一对 (l,r),能够得到 (MEX),对于整个序列的所有的 (l,r),求其所有的 (MEX) 数的 (MEX)。
花絮
之前和WISH2LUCKY讨论了一个鬼畜的MEX问题,然后就让他做了区间MEX的模板题,然后7酱路过,就说起了这题。
做这题之前补了牛客小米邀请赛第一场的E,也就拓宽了一些思路qwq。
思路
已知相同的一个数能将一个序列划分成不同的好几段,假定这个数是答案,例如一个数为 (1),序列为 ({2,1,3,4,1,4,6,7,1,3}),那么划分后能得到 ({2},{3,4},{4,6,7},{3})。如果这个数是不是答案,那么会是这些段的 (MEX)。如果对于所有裁剪出来的,都不是 (MEX),从小到大枚举,那就是答案了!
那么如何证明是裁剪出来的一整段呢?这部分是口胡出来的,证明本当苦手
因为如果是较小的数的话,会将裁剪后的进行进一步切分,所以 出现的 (MEX) 只会变小,因为枚举的数以及不在裁剪后的部分里面了,所以 (MEX) 只会更小,而更小的情况在枚举的时候就能判断掉了。
AC代码
板子很长,跑得挺快
#include <bits/stdc++.h>
#define SZ(x) (int)x.size()
using namespace std;
const int MAXN = 1e5 + 5;
int bep;
class HJT {
public:
struct node {
int lson, rson, maxx;
} T[MAXN * 70];
int tol;
#define ls T[rt].lson
#define rs T[rt].rson
inline void push_up(int rt) {
T[rt].maxx = max(T[ls].maxx, T[rs].maxx);
}
int build(int l, int r) {
int nrt = ++tol;
int mid = (l + r) >> 1;
T[nrt].lson = T[nrt].rson = 0;
T[nrt].maxx = bep;
if (l < r) {
T[nrt].lson = build(l, mid);
T[nrt].rson = build(mid + 1, r);
push_up(nrt);
}
return nrt;
}
int update(int rt, int pos, int v, int be, int en) {
int nrt = ++tol;
if (be == en) {
T[nrt].maxx = v;
return nrt;
}
int mid = (be + en) >> 1;
if (pos <= mid) {
T[nrt].lson = update(T[rt].lson, pos, v, be, mid);
T[nrt].rson = T[rt].rson;
} else {
T[nrt].lson = T[rt].lson;
T[nrt].rson = update(T[rt].rson, pos, v, mid + 1, en);
}
push_up(nrt);
return nrt;
}
int query(int rt, int R, int be, int en) {
if (be == en) return be;
int ans = -1;
int mid = (be + en) >> 1;
if (T[ls].maxx > R) ans = query(T[rt].lson, R, be, mid);
if (ans == -1 && T[rs].maxx > R) ans = query(T[rt].rson, R, mid + 1, en);
return ans;
}
} tree;
int root[MAXN];
int a[MAXN];
vector<int> vec[MAXN];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
bep = n + 1;
root[n + 1] = tree.build(1, n+1);
for (int i = n; i >= 1; i--) {
int x = a[i];
root[i] = tree.update(root[i + 1], x, i, 1, n+1);
}
for (int i = 1; i <= n; i++) {
vec[a[i]].push_back(i);
}
for (int i = 1; i <= n+1; i++) {
int flag = 0;
if (SZ(vec[i]) == 0) {
printf("%d", i+1);
return 0;
}
for (int j = 0; j <= SZ(vec[i]); j++) {
int l, r;
if (j == 0) {
l = 1, r = vec[i][j] - 1;
} else if (j == SZ(vec[i])) {
l = vec[i][j - 1] + 1, r = n;
} else {
l = vec[i][j - 1] + 1, r = vec[i][j] - 1;
}
if (l > r) continue;
else {
int tmp = tree.query(root[l], r, 1, n+1);
if (tmp == -1) continue;
else {
if (tmp == i) {
flag = 1;
}
}
}
}
if (!flag) {
printf("%d
", i);
return 0;
}
}
}