码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ 3659 Conquer a New Region

时间:2015-09-05 22:11:26      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:

题意:给你n个点,以及n-1条边和它的权值。定义S(i,j)为从i到j路径上权值最小的边的权值。求最大的 ∑S(i,j)。j从1到n。

思路:并查集。用point数组维护每一个集合的权值和点的个数,point[i][0]为权值,point[i][1]为集合点数。先将边降序排列。然后枚举每一条边,判断point[u][0]+w*point[v][1]和point[v][0]+w*point[u][1]的大小。如果前者大 就把v点所在集合并入u所在集合,然后把u集合的权值和点数更新,后者大就把u点所在集合并入v所在集合,然后把v集合的权值和点数更新。最后输出仅剩一个集合的权值。

技术分享
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN=210000;
struct Edge{
    int u,v;
    ll w;
}edge[210000];
int n;
ll point[MAXN][2];
int par[MAXN];

bool cmp(Edge a,Edge b)
{
    return a.w>b.w;
}

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

void init()
{
    for(int i=0;i<=n;i++)
        par[i]=i,point[i][1]=1,point[i][0]=0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=0;i<n-1;i++)
            scanf("%d%d%lld",&edge[i].u,&edge[i].v,&edge[i].w);
        sort(edge,edge+n-1,cmp);
        for(int i=0;i<n-1;i++)
        {
            int u=edge[i].u;
            int v=edge[i].v;
            ll w=edge[i].w;
            int x=find(u);
            int y=find(v);

            if(point[x][0]+w*point[y][1]>point[y][0]+w*point[x][1])
            {
                par[y]=x;
                point[x][0]+=w*point[y][1];
                point[x][1]+=point[y][1];
            }
            else
            {
                par[x]=y;
                point[y][0]+=w*point[x][1];
                point[y][1]+=point[x][1];
            }
        }
        printf("%lld\n",point[find(1)][0]);
    }
    return 0;
}
View Code

 

ZOJ 3659 Conquer a New Region

标签:

原文地址:http://www.cnblogs.com/onlyAzha/p/4783955.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!