609E- Minimum spanning tree for each edge

本文详细介绍了如何求解给定边的次小生成树问题,利用了LCA(最近公共祖先)、倍增法和最小生成树等算法,并提供了一个完整的C++实现示例。

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

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.

Examples

Input
5 7
1 2 3
1 3 1
1 4 5
2 3 2
2 5 3
3 4 2
4 5 4
Output
9
8
11
8
8
8
9

次小生成树模板:
lca+倍增+最小生成树
#define eps 1e-6
#define ll long long
#define pii pair<int, int>
#define pb push_back
#define mp make_pair
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int N = 200100;
//*************************
int n, m;
//kruscal
struct tree
{
    int a,b,w;
} p[N],s[N];
int p1[N];
int rk1[N];
//倍增
int fa[N][20], max_e[N][20], dep[N];
//lca
struct edge
{
    int to, nxt,w;
} e[N<<1];
int fst[N], tot;
struct query
{
    int to,nxt;
    int idx;
} Q[N<<1];
int h[N],tt;
int p2[N],rk2[N];
int acr[N], ans[N];
bool vis[N];
//************************
void CLS()
{
    tot = 0;
    memset(fst,-1,sizeof(fst));
    tt = 0;
    for(int i=1; i<=n; i++)p1[i]=i,p2[i]=i;
    memset(h,-1,sizeof(h));
}
void add(int u,int v,int w)
{
    e[++tot].to = v;
    e[tot].w = w;
    e[tot].nxt = fst[u];
    fst[u] = tot;
}
void add_Q(int u,int v,int idx)
{
    Q[++tt].to = v;
    Q[tt].nxt = h[u];
    Q[tt].idx = idx;
    h[u] = tt;
}
//kruscal
bool cmp(tree x,tree y)
{
    return x.w<y.w;
}
int find_p(int x)
{
    return x == p1[x] ? x : p1[x]=find_p(p1[x]);
}
void uone1(int x,int y)
{
    int t1=find_p(x);
    int t2=find_p(y);
    if(t1!=t2)
    {
        if(rk1[t1]>rk1[t2])p1[t2]=t1;
        else p1[t1]=t2;
        if(rk1[t1]==rk1[t2])rk1[t2]++;
    }
}
ll kruscal()
{
    ll res = 0;
    sort(p+1, p+m+1, cmp);
    int cnt=0;
    for (int i = 1; i <= m; i++)
    {
        int x=p[i].a;
        int y=p[i].b;
        int w=p[i].w;
        if(find_p(x)!=find_p(y))
        {
            cnt++;
            uone1(x,y);
            res+=w;
            add(x,y,w);
            add(y,x,w);
            if(cnt==n-1)break;
        }
    }
    return res;
}

//倍增
void init_fa(int u, int p, int w)
{
    dep[u] = dep[p] + 1;
    fa[u][0] = p;
    max_e[u][0] = w;
    for (int i = 1; fa[u][i-1]; i++)
    {
        fa[u][i] = fa[ fa[u][i-1] ][i-1];
        max_e[u][i] = max(max_e[u][i-1], max_e[ fa[u][i-1] ][i-1]);
    }
}

int cal(int u, int lca)
{
    int d = dep[u] - dep[lca];
    int res = 0;
    for(int i = 18; i >= 0; i--)
    {
        if ((1<<i) <= d)
        {
            d -= (1<<i);
            res = max(res, max_e[u][i]);
            u = fa[u][i];
        }
    }
    return res;
}

//LCA
int find_q(int x)
{
    return x == p2[x] ? x : p2[x]=find_q(p2[x]);
}
void uone2(int x,int y)
{
    int t1=find_q(x);
    int t2=find_q(y);
    if(t1!=t2)
    {
        if(rk2[t1]>rk2[t2])p2[t2]=t1;
        else p2[t1]=t2;
        if(rk2[t1]==rk2[t2])rk2[t2]++;
    }
}
void LCA(int u)
{
    vis[u] = 1;
    acr[u] = u;
    for(int p = fst[u]; p != -1; p = e[p].nxt)
    {
        int v = e[p].to;
        if(vis[v]) continue;
        init_fa(v, u, e[p].w);
        LCA(v);
        uone2(u,v);
        acr[find_q(u)] = u;
    }
    for(int p = h[u]; p != -1; p = Q[p].nxt)
    {
        int v = Q[p].to;
        if(vis[v]) ans[Q[p].idx] = acr[find_q(v)];
    }
}

int main()
{
//    freopen("input.txt", "r", stdin);
    scanf("%d%d", &n, &m);
    CLS();
    for (int i = 1; i <= m; i++)
    {
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        p[i].a=s[i].a=a;
        p[i].b=s[i].b=b;
        p[i].w=s[i].w=w;
        add_Q(a,b,i);
        add_Q(b,a,i);
    }
    ll tmp = kruscal();
    LCA(1);
    for (int i = 1; i <= m; i++)
        printf("%I64d\n", tmp+s[i].w-max(cal(s[i].a, ans[i]), cal(s[i].b, ans[i])));
    return 0;
}

 

转载于:https://www.cnblogs.com/planche/p/8910844.html

请用Prim算法完成本题,代码为c++无注释 T-3 Pay Less, Travel More 分数 35 作者 DAI, Longao 单位 杭州百腾教育科技有限公司 There is an undirected graph with N vertices and M edges where the i-th edge has a cost of C i ​ . You start from vertex S and need to reach vertex T. When you pass through an edge, you need to pay c coins, where c is the minimum cost of all edges you have passed (including the current edge you’re passing). More formally, let E 1 ​ ,E 2 ​ ,⋯,E k ​ be a path from vertex S to vertex T, where E i ​ is the i-th edge in the path. The total number of coins you need to pay for this path will be i=1 ∑ k ​ j=1 min i ​ C E j ​ ​ . Your job is to compute the minimum total coins paid between every pair of vertices. More formally, let d(S,T) be the minimum total number of coins you have to pay if you start from vertex S and finally reach vertex T, you need to calculate S=1 ∑ n ​ T=S+1 ∑ n ​ d(S,T). Input Specification: Each input file contains one test case. For each case, the first line contains 2 positive integers N and M (1≤N≤300,1≤M≤50000), which are the number of vertices and that of the edges, respectively. Then M lines follow, each containing 3 numbers X i ​ , Y i ​ , and C i ​ (1≤X i ​ ,Y i ​ ≤N,X i ​ !=Y i ​ ,0≤C i ​ ≤10 ^5 ) for i=1,⋯,M, where X i ​ and Y i ​ are the two ends of an edge, and C i ​ is its cost. It is guaranteed that the given graph is connected. Output Specification: For each case, output in a line the minimum total coins paid between every pair of vertices. Sample Input 1: 8 10 1 2 10 2 3 2 3 6 50 6 8 3 2 4 4 4 6 1 4 5 3 5 8 5 2 7 2000 7 8 8 Sample Output 1: 189 Sample Input 2: 4 3 1 2 10 2 3 10 2 4 1 Sample Output 2: 49 Hint: For sample 1, the path from vertex 1 to 8 is not unique. The following two paths both have a minimum total cost 16: 1−2−3−6−8 (10+2+2+2=16) 1−2−4−6−8 (10+4+1+1=16) For sample 2, the minimum coins paid path from vertex 1 to 3 is: 1−2−4−2−3 (10+1+1+1=13) 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB
最新发布
08-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值