Codeforces Educational Codeforces Round 3 E. Minimum spanning tree for each edge 树上倍增

博客围绕图的最小生成树问题展开,给定一个含n个顶点和m条边的无自环与重边的连通无向加权图,要求找出包含每条边的最小生成树的最小可能权重。题解是先生成最小生成树,加入边产生环后求环的最小值,可使用倍增法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E. Minimum spanning tree for each edge

题目连接:

http://www.codeforces.com/contest/609/problem/E

Description

Connected undirected weighted graph without self-loops and multiple edges is given. Graph contains n vertices and m edges.

For each edge (u, v) find the minimal possible weight of the spanning tree that contains the edge (u, v).

The weight of the spanning tree is the sum of weights of all edges included in spanning tree.

Input

First line contains two integers n and m (1 ≤ n ≤ 2·105, n - 1 ≤ m ≤ 2·105) — the number of vertices and edges in graph.

Each of the next m lines contains three integers ui, vi, wi (1 ≤ ui, vi ≤ n, ui ≠ vi, 1 ≤ wi ≤ 109) — the endpoints of the i-th edge and its weight.

Output

Print m lines. i-th line should contain the minimal possible weight of the spanning tree that contains i-th edge.

The edges are numbered from 1 to m in order of their appearing in input.

Sample Input

5 7

1 2 3

1 3 1

1 4 5

2 3 2

2 5 3

3 4 2

4 5 4

Sample Output

9

8

11

8

8

8

9

Hint

题意

给你一个图,n点m边。对于每个边,问你包含这条边的最小生成树是多少。

题解:

先生成一个最小生成树,加入一条边,可能会产生一个环,那么求这个环的最小值即可,

这个用倍增就行,就和求次小生成树一模一样。

今天typora终于可以用搜狗输入法了,我发现终端打开都用不了搜狗输入法,真奇怪呀。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 400050
ll n,m;
ll dp[N],mm[N],fu[N][21],mx[N][21];
ll tot,last[N];
struct Edge
{
    ll from,to,val,s;
    bool operator < (const Edge&b)
        {return val<b.val;}
}a[N],edges[N];
template<typename T>void read(T&x)
{
    ll k=0; char c=getchar();
    x=0;
    while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
    if (c==EOF)exit(0);
    while(isdigit(c))x=x*10+c-'0',c=getchar();
    x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
void AddEdge(ll x,ll y,ll z)
{
    edges[++tot]=Edge{x,y,z,last[x]};
    last[x]=tot;
}
ll gf(ll x,ll *f)
{
    if (x==f[x])return x;
    return f[x]=gf(f[x],f);
}
ll MST(Edge *edges)
{
    static ll f[N]; static Edge a[N];
    for(ll i=1;i<=m;i++)a[i]=edges[i];
    ll num=0,sum=0;
    sort(a+1,a+m+1);
    for(ll i=1;i<=n;i++)f[i]=i;
    for(ll i=1;i<=m;i++)
    {
        Edge e=a[i];//
        ll fx=gf(e.from,f),fy=gf(e.to,f);
        if (fx!=fy)//
    {
            f[fx]=fy;
            num++;
            sum+=e.val;
            AddEdge(e.to,e.from,e.val);
            AddEdge(e.from,e.to,e.val);
    }
        if (num==n-1)break;
    }
    return sum;
}
void dfs(ll x,ll pre)
{
    dp[x]=dp[pre]+1;
    fu[x][0]=pre;
    for(ll i=last[x];i;i=edges[i].s)
    {
        Edge &e=edges[i];
        if (e.to==pre)continue;
        mx[e.to][0]=e.val;
        dfs(e.to,x);
    }
}
void init_ST(ll n)
{
    mm[0]=-1;
    for(ll i=1;i<=n;i++) mm[i]=(i&(i-1))==0?mm[i-1]+1:mm[i-1];
    for(ll i=1;i<=20;i++)
        for(ll j=1;j<=n;j++)
        {
            fu[j][i]=fu[fu[j][i-1]][i-1];
            mx[j][i]=max(mx[j][i-1],mx[fu[j][i-1]][i-1]);
        }
}
ll get_max(ll x,ll y)
{
    ll ans=0;
    if (dp[x]<dp[y])swap(x,y);
    for(ll i=mm[dp[x]-dp[y]];i>=0;i--)
        if (dp[fu[x][i]]>=dp[y])
        {
            ans=max(ans,mx[x][i]);
            x=fu[x][i];
        }
    if (x==y)return ans;
    for(ll i=mm[dp[x]-1];i>=0;i--)
        if (fu[x][i]!=fu[y][i])
        {
            ans=max(ans,mx[x][i]);
            ans=max(ans,mx[y][i]);
            x=fu[x][i];
            y=fu[y][i];
        }
    ans=max(ans,mx[x][0]);
    ans=max(ans,mx[y][0]);
    return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("aa.in","r",stdin);
#endif
    read(n); read(m);
    for(ll i=1;i<=m;i++)
    {
        ll x,y,z;
        read(x); read(y); read(z);
        a[i]=Edge{x,y,z,0};
    }
    ll sum=MST(a);
    dfs(1,0);
    init_ST(n);
    for(ll i=1;i<=m;i++)
    {
        ll ans=sum-get_max(a[i].from,a[i].to)+a[i].val;
        printf("%lld\n",ans);
    }
}

转载于:https://www.cnblogs.com/mmmqqdd/p/10828878.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值