Kruskal 重构树

定义

从构建的过程来定义。

在 kruskal 算法最小生成树的过程中,我们从小到大得到了 \(n - 1\) 条最小生成树上的边。根据这些边我们重新构造一颗树,具体的,依次遍历上述 \(n - 1\) 条边,对于当前遍历到的边 \((u, v, val)\)(表示节点 \(u\) 和节点 \(v\)之间有一条边权为 \(val\) 的边),我们新建一个点权为 \(val\) 的节点 \(t\),并建立无权边 \((t, root(u))\)\((t, root(v))\)\(root(u)\) 表示 \(u\) 当前所在树的根节点,当然连边后 \(root(u) = root(v) = t\)。依据上述过程我们得到一颗共有 \(2n - 1\) 个节点的树,这棵树就是 kruskal 重构树。

实现

// 并查集
int get(int u) {
    return u == fa[u] ? u : (fa[u] = get(fa[u]));
}
bool merge(int u, int v) {
    int fu = get(u), fv = get(v);
    fa[fv] = fu;
    return fu != fv;
}

void solve() {
    // code ...
    
    // edge 存排好序的边
    int cnt = n;
    for (auto &[u, v, value] : edge) {
        if (merge(u, v)) {
            cnt++; // 新增节点的编号
            fa[u] = fa[v] = cnt;
            val[cut] = value;
            g[cnt].push_back(u); // 建立无权边
            g[cnt].push_back(v);
        }
    }

    // code ...
}

性质

原图中两个点之间的所有简单路径上最大边权的最小值 = 最小生成树上两个点之间的简单路径上的最大值 = kruskal 重构树上两点之间的 LCA 的权值。

第二个等号可以这样理解: kruskal 重构树上两点的 LCA 代表的是这样一条边,在加入这条边前两点不连通而加入这条边后两点才连通。因为在建树时我们是从小到大加边,所以 LCA 的值就应该是最小生成树上两个点之间的简单路径上的最大值。

ABC394 G 可利用上述性质

posted @ 2025-02-28 17:07  Young_Cloud  阅读(37)  评论(0)    收藏  举报