Luogu P6852 Mex(思维)
文章目录
题目描述
给定 $n$ 和 $m$ 条 区间 mex 信息
要求构造一个 $0$ 到 $n$ 的合法排列
简要做法
$mex(l,r) = k$,就是说 区间 $[l,r]$ 内出现过 $[0,k-1]$,没出现过 $k$
那么对于一个 $k$,$k$ 一定要出现的区间即为 $mex > k$ 的区间的交集,$k$ 不能出现的区间即为 $mex = k$ 的区间的并集
考虑从小到大填数,这样一定出现的区间的是不变或者不断拓展的,那么填的时候随便填就可以了
那么可以用一个 set
维护可以放置的位置,每次二分查找即可
$mex = 0$ 的情况特判即可
参考代码
#include <stdio.h>
#include <algorithm>
#include <memory.h>
#include <set>
const int N = 5e5 + 5;
int n, m;
int al[N], ar[N], bl[N], br[N], c[N], ans[N];
std::set<int> S;
int read()
{
int x = 0, f = 1;
char ch = getchar();
while ('0' > ch or ch > '9')
f = ch == '-' ? -1 : 1, ch = getchar();
while ('0' <= ch and ch <= '9')
x = x * 10 + ch - 48, ch = getchar();
return x * f;
}
// a[k] : mex > k 的区间交
// b[k] : mex = k 的区间并
int main()
{
n = read();
for (int i = 0; i <= n; i++)
al[i] = 0, ar[i] = n, bl[i] = n + 1, br[i] = -1, S.insert(i);
for (int m = read(); m--;)
{
int l = read(), r = read(), k = read();
if (k)
al[k - 1] = std::max(al[k - 1], l), ar[k - 1] = std::min(ar[k - 1], r),
bl[k] = std::min(bl[k], l), br[k] = std::max(br[k], r);
else
++c[l], --c[r + 1];
}
for (int i = n - 1; i >= 0; i--)
al[i] = std::max(al[i], al[i + 1]),
ar[i] = std::min(ar[i], ar[i + 1]);
for (int i = 0; i <= n; i++)
{
if (i != 0)
c[i] += c[i - 1];
if (al[0] <= i and i <= ar[0] and c[i] == 0)
{
ans[i] = 0, S.erase(i);
break;
}
}
for (int i = 1; i <= n; i++)
{
std::set<int>::iterator it = S.lower_bound(al[i]);
if (it != S.end() and *it <= ar[i] and (*it < bl[i] or br[i] < *it))
ans[*it] = i, S.erase(it);
else if (br[i] != -1)
{
it = S.lower_bound(br[i] + 1);
if (it != S.end() and *it <= ar[i])
ans[*it] = i, S.erase(it);
}
}
if (!S.empty())
return puts("-1"), 0;
for (int i = 0; i <= n; i++)
printf("%d ", ans[i]);
return 0;
}