社区讨论

关于此题实现细节的疑问

P8276 [USACO22OPEN] Hoof and Brain P参与者 2已保存回复 5

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
5 条
当前快照
1 份
快照标识符
@mhk6f2xj
此快照首次捕获于
2025/11/04 14:16
4 个月前
此快照最后确认于
2025/11/04 14:16
4 个月前
查看原帖
具体见代码注释。我感觉题解到处都是问题但是它就是过了…想知道为什么。
CPP
#include <bits/stdc++.h>

using namespace std;

constexpr int N = 400010;
int n, m, T, q[N], fa[N];
bool vis[N];
unordered_set<int> G[N], s[N];

void toposort() {
    int l = 0, r = -1;
    for (int i = 1; i <= n; i++)
        if (s[i].empty())
            q[++r] = i, vis[i] = true;
    while (l <= r) {
        int u = q[l++];
        for (int v : G[u]) {
            s[v].erase(u);
            if (s[v].empty()) q[++r] = v, vis[v] = true;
        }
    }
}

int find(int u) {
    if (fa[u] != u) fa[u] = find(fa[u]);
    return fa[u];
}

bool merge(int& u, int& v) {
    u = find(u), v = find(v);
    if (u == v) return false;
    // if (rand() & 1) swap(u, v);
    if (G[u].size() > G[v].size()) swap(u, v);
    /*
    1. 如果完全不交换,会陷入死循环
    2. 如果随机交换,也会陷入死循环
    */
    fa[u] = v;
    return true;
}

void toposort_ex() {
    for (int i = 1; i <= n; i++) fa[i] = i;
    int l = 0, r = -1;
    for (int i = 1; i <= n; i++)
        if (s[i].size() == 1)
            q[++r] = i;
    while (l <= r) {
        int u = q[l++], p = *s[u].begin();
        assert(s[u].size() == 1);
        if (!merge(u, p)) continue;
        for (int v : G[u]) {
            //v可能等于u,即在遍历中修改set的值,这可能会死循环,但是实际上没有
            G[p].emplace(v);
            s[v].erase(u);
            s[v].insert(p);//u是p的后继节点时,v=p会为p凭空创造一个自环。自环理论上会影响答案,但是它没对答案造成任何影响。
            if (s[v].size() == 1) q[++r] = v;
        }
        G[u].clear();//此处如果顺便也把出边也删除,同样会WA。但是理论上出边是不是也不需要用了。
    }
}

int main() {
    freopen("10.in", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1, u, v; i <= m; i++) {
        cin >> u >> v;
        G[v].emplace(u); // reverse
        s[u].insert(v);
    }
    toposort();
    toposort_ex();
    cin >> T;
    while (T--) {
        int u, v;
        cin >> u >> v;
        putchar("BH"[!vis[u] && !vis[v] && find(u) != find(v)]);
    }
    putchar('\n');
    return 0;
}
感觉这道题就是在炼仙丹。

回复

5 条回复,欢迎继续交流。

正在加载回复...