洛谷 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)
本文来自博客园,作者:zjsqwq,转载请注明原文链接:https://www.cnblogs.com/zjsqwq/p/16390237.html

浙公网安备 33010602011771号