Minimum spanning tree for each edge CodeForces - 609E

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36616023/article/details/82468972

题意:一个无向图联通中,求包含每条边的最小生成树的值(无自环,无重边)

分析:求出这个图的最小生成树,用最小生成树上的边建图

对于每条边,不外乎两种情况

1:该边就是最小生成树上的边,那么答案显然

2:该边不在最小生成树上,那么进行路径查询,假设加入这条边,那么形成一个环,删去这个环上除该边外的最大权值边,形成一棵树

树的权值即为答案。(并不需要真正加入这条边)

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=201000;
const int inf=0x3f3f3f3f;
int visedge[maxn];
struct edge
{
    int v,nxt;
    long long w;
}edge[maxn*3+100];
int head[maxn],cnt=0;
void add_edge(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
}
struct node
{
    int x,y,z;
    int id;
}a[maxn*3+100],b[maxn*3+100];
int deg[maxn],fa[maxn][20];
long long dis[maxn][20];
int vis[maxn];
void bfs(int u)
{
    queue<int>q;
    q.push(u);
    vis[u]=1;
    fa[u][0]=u;
    deg[u]=0;
    while(!q.empty())
    {
        int now=q.front();
        vis[now]=1;
        q.pop();
        for(int i=1;i<20;i++)
        {
            fa[now][i]=fa[fa[now][i-1]][i-1];
            dis[now][i]=max(dis[now][i-1],dis[fa[now][i-1]][i-1]);
        }
        for(int i=head[now];i!=-1;i=edge[i].nxt)
        {
            int to=edge[i].v;
            if(to==fa[now][0])
            {
                continue;
            }
            deg[to]=deg[now]+1;
            dis[to][0]=edge[i].w;
            fa[to][0]=now;
            q.push(to);
        }
    }
}
int lca(int u,int v)
{
    if(deg[u]>deg[v])
    {
        swap(u,v);
    }
    int hu=deg[u],hv=deg[v];
    int tu=u,tv=v;
    for(int det=hv-hu,i=0;det;det>>=1,i++)
    {
        if(det&1)
        {
            tv=fa[tv][i];
        }
    }
    if(tu==tv)
        return tu;
    for(int i=19;i>=0;i--)
    {
        if(fa[tu][i]==fa[tv][i])
            continue;
        tu=fa[tu][i];
        tv=fa[tv][i];
    }
    return fa[tu][0];
}
int cmp(node aa,node bb)
{
    return aa.z<bb.z;
}
int pre[maxn];
int findd(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    int i=x,j;
    while(i!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}
long long solve(int u,int v)
{
    long long maxx=0;
    int hu=deg[u],hv=deg[v];
    int tu=u,tv=v;
    for(int det=hu-hv,i=0;det;det>>=1,i++)
    {
        if(det&1)
        {
            maxx=max(maxx,dis[tu][i]);
            tu=fa[tu][i];
        }
    }
    return maxx;
}
int main ()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    memset(deg,0,sizeof(deg));
    memset(fa,0,sizeof(fa));
    int m,n;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].z); 
        b[i].x=a[i].x;
        b[i].y=a[i].y;
        b[i].z=a[i].z; 
        a[i].id=i;
    }
    for(int i=1;i<=n;i++)
    {
        pre[i]=i;
    }
    sort(a+1,a+1+m,cmp);
    int nn=0;
    long long sum=0;
    for(int i=1;i<=m;i++)
    {
        int tx,ty;
        tx=findd(a[i].x);
        ty=findd(a[i].y);
        if(tx!=ty)
        {
            visedge[a[i].id]=1;
            pre[ty]=tx;
            sum+=a[i].z;
            add_edge(a[i].x,a[i].y,a[i].z);
            add_edge(a[i].y,a[i].x,a[i].z);
            nn++;
            if(nn==n-1)
            {
                break;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            bfs(i);
        }
    }
    for(int i=1;i<=m;i++)
    {
        if(visedge[i]==0)
        {
            int xx=b[i].x;
            int yy=b[i].y;
            int aa=lca(xx,yy);
            //printf("\n%d %d %d %d\n",xx,yy,solve(xx,aa),solve(yy,aa));
            printf("%lld\n",sum-max(solve(xx,aa),solve(yy,aa))+b[i].z);
        }
        else
        {
            printf("%lld\n",sum);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36616023/article/details/82468972