洛谷-P17524 [ECUSTPC 2026 Fall] 净化行动 3 题解

洛谷-P17524 [ECUSTPC 2026 Fall] 净化行动 3

无限大的棋盘上有 \(n\) 个中国象棋中的炮棋子,它们的坐标固定为 \((x_1, y_1),(x_2, y_2),\cdots,(x_n,y_n)\)。

如果两个炮 \(A\) 和 \(B\) 处于同一行或同一列,且它们的连线上有且仅有一个其他炮 \(C\),那么我们称 \(A\) 和 \(B\) 互相受到对方攻击。

现在可以进行任意多次操作,每一次操作选择一个当前没有受到任何其他炮攻击的炮,并将其摧毁。问最终是否可以清空棋盘。

\(\sum n\le2\cdot10^5\),\(-10^9\le x_i,y_i\le10^9\)。

观察样例可知,如果同一行或同一列上有 \(\ge4\) 个炮,那么它们无论何时都会互相攻击,不可能有未受攻击的炮,故此时无解。只需考虑同一行和同一列的炮不超过 \(3\) 个的情况。

如果同一行 / 列上只有 \(1\) 或 \(2\) 个炮,它们不会互相攻击,没有影响。

如果同一行 / 列上有 \(3\) 个炮,那么只有先将中间的炮摧毁,剩余的两个炮才能被摧毁。

因此我们可以从中间的炮向两边的炮连边,再进行拓扑排序,看能否完成(是否是 DAG)即可。

不需要判断同一行 / 列有多少个炮,因为如果超过 \(3\) 个则一定有环,不可能完成拓扑排序。

#include <bits/stdc++.h>
#define f(i, a, b) for (int i = (a); i <= (b); ++i)
#define g(i, a, b) for (int i = (a); i >= (b); --i)
#define fi first
#define se second
#define pb push_back
#define int ll
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<bool> vb;
typedef vector<ll> vl;
typedef vector<vector<int> > vvi;
typedef vector<pair<int, int> > vii;
int constexpr INF = 0x3f3f3f3f3f3f3f3f;
template <typename T, typename U> constexpr bool gmx(T &a, U b) { return (b > a) ? (a = b, true) : false; }
template <typename T, typename U> constexpr bool gmn(T &a, U b) { return (b < a) ? (a = b, true) : false; }

struct Pao {
  int x, y, id;
};

void solve() {
  int n; cin >> n;
  vector<Pao> a(n + 1);
  f(i, 1, n) {
    cin >> a[i].x >> a[i].y;
    a[i].id = i;
  }

  vvi g;
  g.resize(n + 1);
  vi deg(n + 1);
  sort(a.begin() + 1, a.end(), [](Pao const& p, Pao const& q) { return p.x == q.x ? p.y < q.y : p.x < q.x; });
  f(i, 2, n - 1) {
    if (a[i].x == a[i - 1].x && a[i].x == a[i + 1].x) {
      g[a[i].id].push_back(a[i - 1].id);
      g[a[i].id].push_back(a[i + 1].id);
      deg[a[i - 1].id]++;
      deg[a[i + 1].id]++;
    }
  }
  sort(a.begin() + 1, a.end(), [](Pao const& p, Pao const& q) { return p.y == q.y ? p.x < q.x : p.y < q.y; });
  f(i, 2, n - 1) {
    if (a[i].y == a[i - 1].y && a[i].y == a[i + 1].y) {
      g[a[i].id].push_back(a[i - 1].id);
      g[a[i].id].push_back(a[i + 1].id);
      deg[a[i - 1].id]++;
      deg[a[i + 1].id]++;
    }
  }

  int cnt = 0;
  queue<int> q;
  f(i, 1, n) if (!deg[i]) q.push(i), ++cnt;
  while (!q.empty()) {
    int u = q.front(); q.pop();
    for (int v: g[u]) {
      if (!--deg[v]) q.push(v), ++cnt;
    }
  }
  if (cnt == n) cout << "YES\n";
  else cout << "NO\n";
  return;
}

signed main() {
  cin.tie(0)->sync_with_stdio(false);

  int tt = 1;
  cin >> tt;
  while (tt--) solve();

  return 0;
}
posted @ 2026-09-29 18:52  f2021ljh  阅读(10)  评论(0)    收藏  举报