洛谷-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;
}

浙公网安备 33010602011771号