题意
给定 $n$ 个点,$m$ 条线段。你可以删除其中的 $k$ 条线段,问最终最多有多少点可以不被任何区间覆盖。
$1 \leq n \leq 2 \times 10^5, 2 \leq m \leq 2 \times 10^5, 2 \leq k \leq 10$
在简单版本中,$k = 2$。
题解
首先看简单版本。如果有一个点被覆盖达到 $3$ 次,那么最终这个点不可能不被覆盖,因此可以不考虑这种点。
如果一个点没有被覆盖,那么它最终一定不会被覆盖,因此可以对这种点计数,最后加上即可。
那么剩下情况就是一个点一定被覆盖 $1$ 次或 $2$ 次。
如果两条线段没有交,那么他们的贡献就是区间中仅被覆盖一次的点的个数之和。最终取最大值和次大值相加即可。
如果两条线段有交,那么他们的贡献是相交区间中被覆盖两次的点的个数,加上这两条线段不相交部分的仅被覆盖一次的点的个数之和。
可以使用一个类似于扫描线的东西维护当前点被哪些线段覆盖。
void STRUGGLING([[maybe_unused]] unsigned TEST_NUMBER) {
tp n, m, k, tar = 0, cnt = 0; bin >> n >> m >> k;
mt19937_64 rnd(217);
set<tp> seg;
vector<vector<unsigned long long>> in(n + 1), out(n + 2);
map<tp, tp> sig;
map<pair<unsigned long long, unsigned long long>, tp> db;
while (m--) {
tp l, r, id = rnd(); bin >> l >> r;
in[l].push_back(id);
out[r + 1].push_back(id);
}
for (tp i = 1; i <= n; ++i) {
for (auto& j : out[i]) seg.erase(j);
for (auto& j : in[i]) seg.insert(j);
if (seg.empty()) ++cnt;
else if (seg.size() == 1) ++sig[*seg.begin()];
else if (seg.size() == 2) ++db[make_pair(*seg.begin(), *seg.rbegin())];
}
multiset<tp> tmp;
for (auto& i : sig) tmp.insert(-i.second);
if (tmp.size() > 0) tar -= *tmp.begin();
if (tmp.size() > 1) tar -= *next(tmp.begin());
for (auto& [i, j] : db) tar = max(tar, j + sig[i.first] + sig[i.second]);
bin << tar + cnt << '\n';
}
至于困难版本。。。其实我感觉跟简单版本差不多,加个 DP 就行了。