歌名 - 歌手
0:00

    Stree

    题目

    给出n个点,m条有权边,现对于每一条边,你需要回答出包含这条边的最小生成树的总边权值。

    分析

    首先我们可以构造一个对于这n个点,m条有权边的最小生成树,显然,这是一棵最小的生成树。
    那么这棵生成树的边的答案就是这棵生成树的总边权。
    然后,就要考虑这棵生成树的其他边了。
    在这棵生成树上,如果我们给它加一条新的边,那么,一定会形成一个环。
    所以,我们把这个环中最大的边(当然不是新加入的边啦)删掉,这棵新树的总边权就是答案。
    怎样删掉这个环中最大的边呢?
    发现,实际上就是删掉加入的新边的两个顶点在原树上的路径上最大的边,那么就可以打倍增lca找到最大的边。(想打树链剖分也可以,不拦你)

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const long long maxlongint=2147483647;
    const long long mo=1000000007;
    const long long N=200006;
    using namespace std;
    long long ans[N],way[N][3],n,m,fa[N],sum,bef[N],last[N*2],next[N*2],to[N*2],f[N][20],g[N][20],tot,v[N*2],deep[N];
    void bj(long long x,long long y,long long z)
    {
    	next[++tot]=last[x];
    	last[x]=tot;
    	to[tot]=y;
    	v[tot]=z;
    }
    void q(long long l,long long r)
    {
    	long long i=l,j=r,mid=way[(l+r)/2][0],e;
    	while(i<j)
    	{
    		while(way[i][0]<mid) i++;
    		while(way[j][0]>mid) j--;
    		if(i<=j)
    		{
    			e=way[i][0];
    			way[i][0]=way[j][0];
    			way[j][0]=e;
    			e=way[i][1];
    			way[i][1]=way[j][1];
    			way[j][1]=e;
    			e=way[i][2];
    			way[i][2]=way[j][2];
    			way[j][2]=e;
    			e=bef[j];
    			bef[j]=bef[i];
    			bef[i]=e;
    			i++;
    			j--;
    		}
    	}
    	if(i<r) q(i,r);
    	if(l<j) q(l,j);
    }
    long long get(long long x)
    {
    	if(fa[x]==x) return x;
    	fa[x]=get(fa[x]);
    	return fa[x];
    }
    void dg(long long x,long long y)
    {
    	for(long long i=last[x];i;i=next[i])
    	{
    		long long j=to[i];
    		if(j!=y)
    		{
    			deep[j]=deep[x]+1;
    			g[j][0]=x;
    			f[j][0]=v[i];
    			dg(j,x);
    		}
    	}
    }	
    long long lca(long long x,long long y)
    {
    	long long l;
        if(deep[x]<=deep[y])
        {
            l=x;
            x=y;
            y=l;
        }
        long long p=0;
        for(long long i=log2(n);i>=0;i--)
        {
        	if(deep[g[x][i]]>=deep[y])
        	{
        		p=max(p,f[x][i]);
        		x=g[x][i];
    		}
    	}
        for(long long i=log2(n);i>=0;i--)
        {
        	if(g[x][i]!=g[y][i])
        	{
        		p=max(p,max(f[x][i],f[y][i]));
        		x=g[x][i];
        		y=g[y][i];
    		}
    	}
        if(x!=y) p=max(p,max(f[x][0],f[y][0]));
    	return p;
    }
    int main()
    {
    	freopen("street.in","r",stdin);
    	freopen("street.out","w",stdout);
    	scanf("%lld%lld",&n,&m);
    	for(long long i=1;i<=m;i++)
    	{
    		scanf("%lld%lld%lld",&way[i][1],&way[i][2],&way[i][0]);
    		fa[i]=i;
    		bef[i]=i;
    	}
    	q(1,m);
    	long long k=0;
    	sum=0;
    	for(long long i=1;i<=m,k<n-1;i++)
    	{
    		long long x=get(way[i][1]);
    		long long y=get(way[i][2]);
    		if(x==y) continue;
    		k++;
    		ans[bef[i]]=1;
    		bj(way[i][1],way[i][2],way[i][0]);
    		bj(way[i][2],way[i][1],way[i][0]);
    		sum+=way[i][0];
    		fa[x]=y;
    	}
    	deep[1]=1;
    	dg(1,0);
    	for(long long i=1;i<=log2(n);i++)
    		for(long long j=1;j<=n;j++)
    		{
    			g[j][i]=g[g[j][i-1]][i-1];
    			f[j][i]=max(f[j][i-1],f[g[j][i-1]][i-1]);
    		}
    	for(long long i=1;i<=m;i++)
    	{
    		if(!ans[bef[i]])
    		{
    			ans[bef[i]]=sum-lca(way[i][1],way[i][2])+way[i][0];
    		}
    		else 
    			ans[bef[i]]=sum;
    	}
    	for(long long i=1;i<=m;i++)
    		printf("%lld\n",ans[i]);
    }
    
    posted @ 2018-05-09 12:28  无尽的蓝黄  阅读(1202)  评论(0编辑  收藏  举报