BZOJ3732:Network kruskal重构树

题面
kruskal重构树:kruskal的过程中每通过一条边合并两个集合 就新建一个结点作为代表这两个集合的结点的父亲,点权为该边边权
叶子结点都是原图中的点==
那么不难发现父节点点权都大于子节点
刚好使询问的两点所在集合合并的边的边权就是所求 即重构树上lca的点权

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 30007;
#define ll long long;
int n, m, q, res, c;
struct edge{
    int u, v, w;
    bool operator < (const edge &rhs) const {
        return w < rhs.w;
    }
}e[maxn << 1];
vector<int> adj[maxn << 1];
int dep[maxn << 1], top[maxn << 1], son[maxn << 1], dfl[maxn << 1], tot, siz[maxn << 1], w[maxn << 1], f[maxn << 1];
int fa[maxn << 1];
int get(int x){return fa[x] == x ? x : fa[x] = get(fa[x]);}
int read(){
    int s = 0; char c = getchar();
    while (c > '9' || c < '0') c = getchar();
    while (c >= '0' && c <= '9') {
        s = s * 10 + c - '0';
        c = getchar();
    }
    return s;
}
void dfs1(int u) {
    siz[u] = 1;
    for (int i = 0; i < adj[u].size(); i++) {
        int v = adj[u][i];
        dep[v] = dep[u] + 1;
        f[v] = u;
        dfs1(v);
        siz[u] += siz[v];
        if (siz[v] > siz[son[u]]) son[u] = v;
    }
}
void dfs2(int u, int t){
    dfl[u] = ++tot; top[u] = t;
    if (son[u]) {
        dfs2(son[u], t);
        for (int i = 0; i < adj[u].size(); i++) {
            int v = adj[u][i];
            if (v != son[u] && v != f[u]) dfs2(v, v);
        }
    }
}
int lca(int u, int v) {
    while (top[u] ^ top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        u = f[top[u]];
    }
    return dep[u] < dep[v] ? u : v;
}
int main(){
    n = read(), m = read(), q = read();
    for (int i = 1; i <= m; i++) e[i].u = read(), e[i].v = read(), e[i].w = read();
    sort(e + 1, e + m + 1);
    for (int i = 1; i <= n << 1; i++) fa[i] = i;
    c = n;
    for (int i = 1, r = n - 1; i <= m && r > 0; i++) {
        int u = get(e[i].u), v = get(e[i].v);
        if (u ^ v) {
            w[++c] = e[i].w;
            fa[u] = fa[v] = c;
            adj[c].push_back(u); adj[c].push_back(v);
            r--;
        }
    }
    dfs1(c); dfs2(c, c);
    for (int i = 1; i <= q; i++) {
        printf("%d\n", w[lca(read(), read())]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值