文章目录

CF1889C Doremy's Drying Plan 做题笔记

发布于

题意

给定 $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 就行了。


暂无评论

发表评论