Complicated Computations

首先可以发现答案小于等于 n+2n+2.于是可以考虑枚举 xx,判断 xx 是否为一个子段的 mex\operatorname{mex}

考虑如果 xxmex\operatorname{mex} 的条件是什么?区间内没有 xx,但包含 1x11 \sim x-1。我们不需要关心 x+1x+1 或以上的数是否有出现。

所以我们可以将序列分成若干段,每一段都不含 xx,但其两边的数要么是 xx,要么这个区间的左端为 11 或右端为 nn。我们只需要判断这些区间的 mex\operatorname{mex} 是否为 xx

当然可以离线莫队加值域分块做,但我们也可以从前往后扫每个数,记录 lstilst_iii 这个数在当前扫描到的前缀中最后的出现位置。当我们扫到 ai=xa_i=x,判断 lstx+1i1lst_x+1 \sim i-1 这个区间是否出现了 1x11 \sim x-1 每个数,即 minj=1x1lstj>lstx\min \limits_{j=1}^{x-1} lst_j > lst_x。然后更新 lstxlst_x

权值线段树维护单点修改区间最小值即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int N = 1e5 + 10;
int n, a[N];
int lstpos[N];
bool vis[N];

class SegmentTree
{
public:
	struct Node
	{
		int l, r, minn;
	}tr[N << 2];
	void pushup(int u)
	{
		tr[u].minn = min(tr[u << 1].minn, tr[u << 1 | 1].minn);
	}
	void build(int u, int l, int r)
	{
		tr[u] = { l, r, 0 };
		if (l == r) return;
		int mid = l + r >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
	}
	void update(int u, int x, int v)
	{
		if (tr[u].l == tr[u].r)
		{
			tr[u].minn = v;
			return;
		}
		int mid = tr[u].l + tr[u].r >> 1;
		if (x <= mid) update(u << 1, x, v);
		else update(u << 1 | 1, x, v);
		pushup(u);
	}
	int query(int u, int l, int r)
	{
		if (tr[u].l >= l and tr[u].r <= r) return tr[u].minn;
		int res = 2e9, mid = tr[u].l + tr[u].r >> 1;
		if (l <= mid) res = query(u << 1, l, r);
		if (r > mid) res = min(res, query(u << 1 | 1, l, r));
		return res;
	}
}sgt;

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	sgt.build(1, 1, n);
	for (int i = 1; i <= n; i++)
	{
		if (a[i] ^ 1)
		{
			vis[1] = 1;
		}
		else
		{
			lstpos[a[i]] = i;
			sgt.update(1, a[i], i);
			continue;
		}
		int p = sgt.query(1, 1, a[i] - 1);
		if (p > lstpos[a[i]])
		{
			vis[a[i]] = 1;
		}
		lstpos[a[i]] = i;
		sgt.update(1, a[i], i);
	}
	for (int i = 2; i <= n + 1; i++)
	{
		if (sgt.query(1, 1, min(n, i - 1)) > lstpos[i])
		{
			vis[i] = 1;
		}
	}
	for (int i = 1; i <= n + 2; i++)
	{
		if (!vis[i])
		{
			printf("%d\n", i);
			return 0;
		}
	}
	return 0;
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示