洛谷 P4137 Rmq Problem / mex 解题报告

洛谷 P4137 Rmq Problem / mex 解题报告

[link](P4137 Rmq Problem / mex - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

题意

有一个长度为 \(n\) 的数组 \(\{a_1,a_2,\ldots,a_n\}\)

\(m\) 次询问,每次询问一个区间内最小没有出现过的自然数。

Solutions

要求区间[mex]((2条消息) 【数学】mex是什么_weixin_30537391的博客-CSDN博客)。

根据\(mex\)的性质不难发现,答案最大为\(n + 1\),因为就算\(n\)个数是\(1\)~\(n\)的形式,答案也是\(n + 1\),反之若不是完全稠密排列,会在比\(n\)小的情况下就出现\(mex\),所以我们 根本不需要离散化,因为有用的数最大只会是\(n+1\),即 直接把大于\(n\)的数变成\(n+1\)就好

然后直接跑莫队,用值域分块优化,如果区间\(i\) \(L[i]\) ~ \(R[i]\)的所有数都出现过,就跳过;如果有没出现过的数,说明\(mex\)就在这块里,直接暴力找就行了。查询时间复杂度是\(\sqrt{n}\)级的。

暴力离散化只有\(90pts\)(悲

时间复杂度:\(O(n \times (\sqrt{n} + \sqrt{n})) \hspace{1mm}= \hspace{1mm} O(n \times\sqrt{n})\)

Code

#include <bits/stdc++.h>

using namespace std;

void rei() {}
template<class T, class... Args> void rei(T &x, Args&... args) {
	x = 0; char ch; bool f = 1;
	while (!isdigit(ch = getchar())) f = ch != '-';
	do x = x * 10 + (ch & 15); while (isdigit(ch = getchar()));
	if (!f) x = -x;
	rei(args...);
}

const int MN = 2e5 + 5;

int n, m, block, sum;
int a[MN], cnt[MN], belong[MN], tot[MN], ans[MN], L[MN], R[MN];
struct Query {
	int l, r, id;
	bool operator < (const Query &x) const {
		return belong[l] != belong[x.l] ? belong[l] < belong[x.l] : belong[l] & 1 ? r < x.r : r > x.r;
 	}
} q[MN];

void add(int x) {
	if (!cnt[x]) tot[belong[x]]++;
	cnt[x]++;
}

void del(int x) {
	cnt[x]--;
	if (!cnt[x]) tot[belong[x]]--;
}

int query() {
	for (int i = 1; i <= belong[n]; ++i) {
		if (tot[i] == R[i] - L[i] + 1) continue;
		for (int j = L[i]; j <= R[i]; ++j)
			if (!cnt[j]) return j;
	}
	return n;
}

signed main() {
	rei(n, m), block = pow(1.0 * (n + 2), 0.55) + 1;
	for (int i = 1; i <= n; ++i) rei(a[i]), a[i] = min(a[i] + 1, n + 2);
	n += 2;
	for (int i = 1; i <= n; ++i) belong[i] = (i - 1) / block + 1;
	for (int i = 1; i <= belong[n]; ++i) {
		L[i] = (i - 1) * block + 1;
		R[i] = i * block;
	}
	for (int i = 1; i <= m; ++i) {
		cin >> q[i].l >> q[i].r;
		q[i].id = i;
	}
	sort(q + 1, q + 1 + m);
	for (int i = 1, l = 1, r = 0; i <= m; ++i) {
		while (l > q[i].l) add(a[--l]);
		while (r < q[i].r) add(a[++r]);
		while (l < q[i].l) del(a[l++]);
		while (r > q[i].r) del(a[r--]);
		ans[q[i].id] = query();
	}
	for (int i = 1; i <= m; ++i) cout << ans[i] - 1 << '\n';
	return 0;
}

Data

暴力离散化\(90pts\)题解 P4137 【Rmq Problem / mex】 - Crpboy's Blog - 洛谷博客 (luogu.com.cn)

AC做法:题解 P4137 【Rmq Problem / mex】 - 一叶知秋。 的博客 - 洛谷博客 (luogu.com.cn)

posted @ 2022-06-19 11:57  zjsqwq  阅读(68)  评论(0)    收藏  举报