题意:
给出一个树形图和边权值,边权值是容量,问把某个点作为首都,向其他n-1个点运输货物,货物容量不超过路径上的边权值;问可以输出的最大货物是多少?
思路:
因为限制条件是路径上的最小值,那么我们按价值排序,从大到小排,就可以避免这个问题了,然后利用并查集来完成,对于两个集合,左集合的价值总和为A,右集合的价值总和为B,现在有一条路径连接这两个集合,那么我们考虑的是将A合并到B还是将B合并到A,我们可以这么比较,连接这两个集合的路径肯定是目前最小的价值,如果A集合元素个数为Ai,那么将A合并到B则B需要加A*Ai,反过来A则加B*Bi,比较哪个大就行了,因为它们一定是合并成一块了,价值大的留下
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define N 200005
struct Edge
{
int u, v;
LL w;
bool operator < (const Edge &other) const
{
return w>other.w;
}
}edge[N];
int fa[N];
LL sum[N], num[N];
int getf(int x)
{
return fa[x]==x?x:fa[x]=getf(fa[x]);
}
LL solve(int n)
{
for(int i=0; i<n-1; i++)
{
int u=getf(edge[i].u);
int v=getf(edge[i].v);
if(sum[u]+num[v]*edge[i].w>=sum[v]+num[u]*edge[i].w)
{
fa[v]=u;sum[u]+=num[v]*edge[i].w;
num[u]+=num[v];
}
else
{
fa[u]=v;sum[v]+=num[u]*edge[i].w;
num[v]+=num[u];
}
}
return sum[getf(1)];
}
int main()
{
int n;
while(scanf("%d", &n)!=EOF)
{
for(int i=0; i<n-1; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[i].u=u;edge[i].v=v;edge[i].w=w;
}
sort(edge, edge+n-1);
for(int i=1; i<=n; i++)
{
fa[i]=i;sum[i]=0;num[i]=1;
}
LL ans=solve(n);
printf("%I64d\n", ans);
}
return 0;
}