UVA 11354 Bond 最小生成树 + lca

题意

给出一张图,q个询问,每次询问给出uv,找出一条路径,使这条路径上的最大边权是两点所有路径中最小,输出这个值

思路

很显然要先求出最小生成树,任意两点在最小生成树上有唯一路径,并且这条路径上的最大边权就是所输出的值,接下来就是如何求出树上任意两点唯一路径中的最大边权了,先把最小生成树转化为有根树,并用fa数组表示u的父亲节点,cost数组表示与父亲节点连的边的边权,dep数组表示这个点的深度,对于每次查询,先把两点的深度调到一样大,同时更新最大边,然后一起向上搜索直到两点的最近公共祖先,同时也更新最大边。这就是最朴素的求LCA的方法。

 

C++代码

 

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 7;

struct Edge{
    int from,to;
    int w,nxt;
}edge[maxn << 2],e[maxn << 2];

int n , m ;
int pre[maxn];
int fa[maxn],cost[maxn],dep[maxn];
int head[maxn],tot;

void init(){
    tot = 0;
    memset(head,-1,sizeof head);
    for(int i = 1;i <= n ; i++){
        pre[i] = i;
    }
}

bool cmp(Edge a,Edge b){
    return a.w < b.w;
}

void add_edge(int u ,int v,int w){
    e[tot].from = u;
    e[tot].to = v;
    e[tot].w = w;
    e[tot].nxt = head[u];
    head[u] = tot ++;
}

inline int find(int x){if(x == pre[x])return x;else return pre[x] = find(pre[x]);}

void kruskal(){
    sort(edge+1,edge+1+m,cmp);
    int fu,fv,u,v;
    for(int i = 1;i <= m; i++){
        u = edge[i].from;
        v = edge[i].to;
        fu = find(u);
        fv = find(v);
        if(fu != fv){
            pre[fu] = fv;
            add_edge(u,v,edge[i].w);
            add_edge(v,u,edge[i].w);
        }
    }
}

void dfs(int u,int Fa,int step){
    int v;
    for(int i = head[u]; ~i ;i = e[i].nxt){
        v = e[i].to;
        if(v ==Fa) continue;
        dep[v] = step;
        fa[v] = u;
        cost[v] = e[i].w;
        dfs(v,u,step + 1);
    }
}

int lca(int u,int v){
    int du = dep[u];
    int dv = dep[v];
    int res = 0;
    while(du > dv){
        res = max(res,cost[u]);
        u = fa[u];
        du --;
    }
    while(dv > du){
        res = max(res,cost[v]);
        v = fa[v];
        dv --;
    }
    while(u != v){
        res = max(res,cost[u]);
        res = max(res,cost[v]);
        u = fa[u];
        v = fa[v];
    }
    return res;
}

int main(){
    int cas = 0;
    while(cin >> n >> m){
        if(cas) puts("");
        else cas ++;
        init();
        for(int i = 1;i <= m; i ++){
            int u , v , w;
            cin >> u >> v >> w;
            edge[i].from = u;
            edge[i].to = v;
            edge[i].w = w;
        }
        //cout << 1 ;
        kruskal();
        fa[1] = cost[1] = dep[1] = 0;
        dfs(1,-1,1);
        int q;
        cin >> q;
        while(q--){
            int u , v ;
            cin >> u >> v;
        cout << lca(u,v) << endl;
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/DWVictor/p/11271520.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值