P8276 [USACO22OPEN] Hoof and Brain P
首先可以注意到,如果某个棋子所在的点没有出边,那么甲只需要选择这个棋子就能够获胜。
于是我们可以将这些点标记,然后将它们从原图中删除。但在完成删除操作后,可能又会有新的节点出边数量变成了
现在我们考虑一个只有
合并后,新图中的所有点都有至少
于是,对于询问
若
使用启发式合并 set 维护每个节点的出边集合
#include <bits/stdc++.h>
#define ins insert
#define era erase
using namespace std;
const int N = 2e5 + 5;
int n, m, k, fa[N];
set <int> f[N], g[N]; // f : out, g : in
queue <int> q;
int gf(int x) {
return x == fa[x] ? x : fa[x] = gf(fa[x]);
}
int main() {
ios :: sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++)
fa[i] = i;
for (int i = 1, x, y; i <= m; i++) {
cin >> x >> y;
f[x].ins(y);
g[y].ins(x);
}
for (int i = 1; i <= n; i++)
if (f[i].size() == 0) q.push(i);
while (!q.empty()) {
int v = q.front();
q.pop();
fa[v] = 0;
for (auto u : g[v]) {
f[u].era(v);
if (f[u].size() == 0) q.push(u);
}
}
for (int i = 1; i <= n; i++)
if (f[i].size() == 1) q.push(i);
while (!q.empty()) {
int x = q.front();
q.pop();
int y = 0;
for (auto v : f[x]) y = v;
x = gf(x);
y = gf(y);
if (x == y) continue;
if (g[x].size() > g[y].size())
swap(x, y);
for (auto z : g[x]) {
f[z].era(x);
f[z].ins(y);
g[y].ins(z);
if (f[z].size() == 1) q.push(z);
}
fa[x] = y;
}
cin >> k;
while (k--) {
int x, y; cin >> x >> y;
x = gf(x);
y = gf(y);
if (x == 0 || y == 0 || x == y) {
cout << "B";
} else {
cout << "H";
}
}
return 0;
}