codeforeces 609E Minimum spanning tree for each edge MST +LCA

12 篇文章 0 订阅
8 篇文章 0 订阅

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.

Example
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

题意:给一个图,有m条边n个点,如果对于一个最小生成树中要求必须包括第i条边,那么最小生成树的权值总和最小是多少
思路:求出最小生成树,然后对于m条边相当于m次查询,每次查询的时候,相当于求出在最小生成树中(u,v)路径上的边权最大值,那么新添加了一条边,就要把这条最大值的边删掉。所以题目转换成了,求路径上边权最大值。可以用LCA来做,也可以用树链剖分来维护。

遗忘点1,fa的父根应该是父节点
遗忘点2,一开始全标记为-1,然后加个判断消掉根节点的影响。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+100;
typedef long long ll;
int mx[N][21],fa[N][21],f[N],deep[N];
int tot,n,m,head[N];
ll ans[N];
ll mincost;
struct node{
    int x,y,w,id;
}bian[N+100];

struct Edge
{
    int v,nxt,w;
}E[2*N+300];

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

int cmp(node a,node b){
    return a.w<b.w;
}

int find(int x)
{
    return x==f[x]?f[x]:f[x]=find(f[x]);
}

void add(int u,int v,int w)
{
    E[tot].v=v;
    E[tot].w=w;
    E[tot].nxt=head[u];
    head[u]=tot++;
}

void merge(int x,int y,int c)
{
    int f1=find(x);
    int f2=find(y);
    if(f1!=f2)
    {
        f[f1]=f2;
        add(x,y,c);
        add(y,x,c);
        mincost+=c;
    }
}

void dfs(int x,int de)
{
    deep[x]=de;
    for(int i=head[x];i!=-1;i=E[i].nxt)
    {
        int vv=E[i].v;
        if(!deep[vv])
        {
            fa[vv][0]=x;//遗忘点1,fa的父根应该是父节点 
            mx[vv][0]=E[i].w;
            dfs(vv,de+1);
        }
    }
}

void ST()
{
    for(int j=1;(1<<j)<=n;j++)
    {
        for(int i=1;i<=n;i++)
        {
            if(fa[i][j-1]!=-1)//遗忘点2,一开始全标记为-1,然后加个判断消掉根节点的影响。
            {
                fa[i][j]=fa[fa[i][j-1]][j-1];
                mx[i][j]=max(mx[i][j-1],mx[fa[i][j-1]][j-1]);
            }
        }
    }
}

int lca(int a,int b)
{
    if(deep[a]<deep[b]) swap(a,b);
    int t=deep[a]-deep[b];
    int maxx=0;
    for(int i=0;i<=20;i++)
    {
        if((1<<i)&t)
        {
            maxx=max(maxx,mx[a][i]);
            a=fa[a][i];
        }
    }
    if(a==b) return maxx;
    for(int i=20;i>=0;i--)
    {
        if(fa[a][i]!=fa[b][i])
        {
            maxx=max(maxx,mx[a][i]);
            maxx=max(maxx,mx[b][i]);
            a=fa[a][i];
            b=fa[b][i];
        }
    }
    maxx=max(mx[a][0],maxx);
    maxx=max(mx[b][0],maxx);
    return maxx;
}


int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        bian[i].x=a,bian[i].y=b;
        bian[i].w=c,bian[i].id=i;
    }
    sort(bian+1,bian+1+m,cmp);
    for(int i=1;i<=m;i++)
    {
        merge(bian[i].x,bian[i].y,bian[i].w);
    }
    dfs(1,1);
    ST();
    for(int i=1;i<=m;i++)
    {
        ans[bian[i].id]=mincost-(ll)lca(bian[i].x,bian[i].y)+(ll)bian[i].w;
    }
    for(int i=1;i<=m;i++)
    {
        printf("%lld\n",ans[i] );
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值