来源 :HDU-4424
题意 :给定n个结点的树,求以哪个点为根得到的承载量最大。C(u,v) 表示u,v之间的承载量,它等于u,v之间最小的边权值。
解法 :将边从大到小排序,进行添边。则新添的边为已经添加的边中的最小值。再进行合并操作,
按照value[u]=num[v]*w+value[u],将value值小的结点合并到大的结点中。
代码段 :
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define LL long long
#define debug(x) cout<<#x<<"="<<x<<endl;
#define LL long long
using namespace std;
const int N=200007;
struct edge
{
int u,v;
LL w;
}e[N];
bool operator < (edge a,edge b)
{
return a.w>b.w;
}
struct fa
{
int pa;//集合中的根节点
int num;//集合中结点个数
LL value;//集合的最大承载量
}Fa[N];
int find(int x)
{
if(Fa[x].pa==x)return x;
return Fa[x].pa=find(Fa[x].pa);
}
void init(int n)
{
rep(i,1,n+1)
{
Fa[i].pa=i;
Fa[i].num=1;
Fa[i].value=0;
}
}
//合并操作
LL unionSet(int bigger,int smaller,LL det)
{
Fa[smaller].pa=bigger;
Fa[bigger].num+=Fa[smaller].num;
//Fa[bigger].value+=Fa[smaller].value;
Fa[bigger].value=det;
return Fa[bigger].value;
}
int main(void)
{
int n;
while(scanf("%d",&n)!=EOF)
{
init(n);
LL res;
rep(i,0,n-1)scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
sort(e,e+n-1);
//插入边
rep(i,0,n-1)
{
int u=e[i].u;int v=e[i].v;LL w=e[i].w;
//debug(w);
int fu=find(u);
int fv=find(v);
LL maxv=Fa[fu].num*1ll*w+Fa[fv].value;
LL maxu=Fa[fv].num*1ll*w+Fa[fu].value;
if(maxv>maxu)res=unionSet(fv,fu,maxv);
else res=unionSet(fu,fv,maxu);
}
printf("%lld\n",res);
}
return 0;
}