609E - Minimum spanning tree for each edge

给出一个带权图,对每个边求经过这条边的MST


先求一遍MST自然是极好的,然后对于在MST上的边,自然就是全局MST了

对于不在MST上的边,找到这个边两个端点在MST上的路径上最大权的边并去掉,然后加上询问的这条边的权就好了

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

const int maxn = 212345,maxm = 212345,max_log = 18;
const int ROOT = 1;
vector<pair<int,LL> >edge[maxn];
void Link(int st,int ed,LL v){
    edge[st].push_back(make_pair(ed,v));
}

int deep[maxn],fa[maxn][max_log];
int nofa[maxn];

struct Info{
    LL x;
    Info(LL x = 0):x(x){};
};

Info operator + (const Info a,const Info b){
    return Info(max(a.x,b.x));
}

Info info[maxn][max_log];

void dfs(int st,int Fa,int Deep=1){
    for(int i=1;i<max_log;i++)
        fa[st][i] = -1,info[st][i] = Info();
    fa[st][0] = Fa,deep[st] = Deep;
    for(auto x : edge[st]){
        if(x.first == Fa) continue;
        dfs(x.first,st,Deep+1);
        info[x.first][0] = Info(x.second);
    }
}
void init(int n){
    memset(fa,-1,sizeof(fa));
    dfs(ROOT,-1);
    for (int j = 1;j < max_log;j++){
        for (int i = 1;i <= n;i++){
            if (fa[i][j-1] != -1){
                fa[i][j] = fa[fa[i][j-1]][j-1];
                info[i][j] = info[i][j-1] + info[fa[i][j-1]][j-1];
            }
        }
    }
}

pair<int,Info> lca(int x,int y){
    Info ix,iy;
    if (deep[x] < deep[y]) swap(x,y);
    for (int i = max_log-1;i >= 0;i--){
        if (deep[fa[x][i]] >= deep[y]){
            ix = ix + info[x][i];
            x = fa[x][i];
        }
    }
    if (x == y) return make_pair(x,ix);
    for (int i = max_log-1;i >= 0;i--){
        if (fa[x][i] != fa[y][i]){
            ix = ix + info[x][i]; x = fa[x][i]; 
            iy = iy + info[y][i]; y = fa[y][i]; 
        }
    }
    return make_pair(fa[x][0], ix/*.rev()*/+info[x][0] + info[y][0] + iy);
}

struct Edge{
    int x,y;
    LL v,i;
    void init(int id){
        scanf("%d %d %I64d",&x,&y,&v);
        i = id;
    }
}edg[maxm];

struct Dsu{
    int arr[maxn];
    void init(int n){for(int i=0;i<=n;i++) arr[i] = i;}
    int fnd(int x){return x == arr[x] ? x : arr[x] = fnd(arr[x]);}
    bool join(int x,int y){
        x = fnd(x),y = fnd(y);
        if(x == y) return false;
        arr[x] = y;
        return true;
    }
}dsu;

int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++){
        edg[i].init(i);
    }
    sort(edg,edg+m,[](Edge a,Edge b){return a.v < b.v;});
    dsu.init(n);
    LL all = 0;
    for(int i=0;i<m;i++){
        if(dsu.join(edg[i].x,edg[i].y)){
            all += edg[i].v;
            Link(edg[i].x,edg[i].y,edg[i].v);
            Link(edg[i].y,edg[i].x,edg[i].v);
        }
    }
    init(n);
    sort(edg,edg+m,[](Edge a,Edge b){return a.i < b.i;});
    for(int i=0;i<m;i++){
        printf("%I64d\n",all + edg[i].v - lca(edg[i].x,edg[i].y).second.x);
    }
    return 0;
}
以下是使用Matlab实现最小生成树(MST)算法的示例代码: ``` function [T, W] = mst_prim(A) % MST_PRIM Minimum Spanning Tree using Prim's algorithm % [T, W] = MST_PRIM(A) computes the minimum spanning tree T and its weight % W of the graph A using Prim's algorithm. % % Input: % A - n-by-n adjacency matrix of the graph. % % Output: % T - n-by-n sparse matrix of the minimum spanning tree. T(i,j) = 1 if % there is an edge between i and j in the minimum spanning tree, % and 0 otherwise. % W - the weight of the minimum spanning tree. % % Author: Zhiqiang Wang, zwang@ieee.org % Date: 07/01/2018 n = size(A, 1); % number of vertices T = sparse(n, n); % initialize the minimum spanning tree W = 0; % initialize the weight of the minimum spanning tree key = inf(1, n); % the minimum key value of each vertex pi = zeros(1, n); % the parent vertex of each vertex visited = false(1, n); % the visited flag of each vertex key(1) = 0; % start from vertex 1 for i = 1:n % find the unvisited vertex with the minimum key value u = find(~visited & (key == min(key)), 1); visited(u) = true; if pi(u) ~= 0 T(u, pi(u)) = 1; % add the edge to the minimum spanning tree T(pi(u), u) = 1; W = W + A(u, pi(u)); % update the weight of the minimum spanning tree end % update the key values of the adjacent vertices for v = 1:n if A(u, v) ~= 0 && ~visited(v) && A(u, v) < key(v) key(v) = A(u, v); pi(v) = u; end end end ``` 该代码使用Prim算法,输入为一个n-by-n的邻接矩阵A,输出为一个n-by-n的稀疏矩阵T和最小生成树的权重W。其中,稀疏矩阵T中T(i,j)=1表示最小生成树中存在一条从i到j的边,否则T(i,j)=0。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值