社区讨论

题解区很离谱

P5163WD与地图参与者 3已保存回复 2

讨论操作

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

当前回复
2 条
当前快照
1 份
快照标识符
@mkia3iub
此快照首次捕获于
2026/01/17 20:23
上个月
此快照最后确认于
2026/01/20 17:20
4 周前
查看原帖
我在讲这道题目的时候,机房大神问我,不是直接并查集就行了吗,我思考着题解的可撤销并查集陷入了沉思。很显然,我的大脑过载了。
但是这样写确实是对的,直接并查集合并就行,没必要撤销,无法理解题解所说的。
核心代码:
CPP
void solve(int l, int r, vector<int> &v) {
    if (v.empty()) return;
    if (l == r) {   
        for (int &x : v) E[x].t = l;
        return;
    }
    int mid = (l + r) >> 1;
    vector<int> ll, rr, fl;
    init();
    for (int &x : v) {
        if (E[x].t <= mid) addedge(E[x].u, E[x].v), ll.push_back(x);
        else rr.push_back(x);
    }
    for (int &x : tmp) {
        if (!dfn[x]) tarjan(x);
    }
    
    vector<pair<int, int> > need; // 需要连起来的边
    for (int &x : ll) {
        if (block[E[x].u] == block[E[x].v]) fl.push_back(x), need.push_back({E[x].u, E[x].v});
        else rr.push_back(x);
    }
    solve(l, mid, fl);

    for (auto &x : need) { // 用并查集的根代表这个强连通分量即可
        f[find(x.second)] = find(x.first);
    }
    for (int &x : rr) {
        E[x].u = find(E[x].u);
        E[x].v = find(E[x].v);
    }
    solve(mid + 1, r, rr);
}

回复

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

正在加载回复...