长春现场赛E题 zoj 3659

E:想法很巧妙的题目。
从大到小排序边加入,设每次边两边的连通块分别为x,y,边权为c,那么将x块与y块合并,x块中

点要增加的边权就是|y|×c,y块增加的边权就是|x|*c。可以用并查集实现合并,同时合并后只需

要将并查集的头设为当前块中边权和最大的点,每次只要维护一个点即可。

代码如下:

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#define maxn 200005

int fa[maxn],cnt[maxn];
long long total[maxn];

struct node
{
    int a,b,c;
}edge[maxn];

int cmp(const void *a,const void *b)
{
    node *aa=(node*)a,*bb=(node*)b;
    return bb->c-aa->c;
}

int find(int x)
{
    int temp=x;
    while(temp!=fa[temp])
        temp=fa[temp];
    fa[x]=temp;
    return temp;
}


int main( )
{
    int n,i,x,y,a,b,c;
    long long temp1,temp2;
    while(~scanf("%d",&n))
    {
        for(i=0;i<=n;i++)
        {
            fa[i]=i;
            cnt[i]=1;
            total[i]=0;
        }
        for(i=0;i<n-1;i++)
            scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].c);
        qsort(edge,n-1,sizeof(node),cmp);
        for(i=0;i<n-1;i++)
        {
            a=edge[i].a;b=edge[i].b;c=edge[i].c;
            x=find(a);y=find(b);
            temp1=(long long)cnt[y]*c+total[x];
            temp2=(long long)cnt[x]*c+total[y];
            if(temp1>temp2)
            {
                fa[y]=x;
                total[x]=temp1;
                cnt[x]+=cnt[y];
            }
            else
            {
                fa[x]=y;
                total[y]=temp2;
                cnt[y]+=cnt[x];
            }
        }
        printf("%lld\n",total[find(1)]);
    }
    return 0;
}


    

    

 

posted @ 2012-10-17 17:11  朝圣の路  阅读(146)  评论(0编辑  收藏  举报