记录下自己的思路。。
题意大概就是N个点N-1条边,两个点之间的运输量记录为两点路径上边权的最小值,求从哪一点出发到剩下点得运输量和最大,输出最大的运输量总和。
首先很明显这些点构成一棵树,那么每一条边都可以把原树分成两个部分。可以把最开始的树看成一个集合,在把所有边从小到大排序,那么当前插入的边可以把所在的集合分成两个集合,而两个集合中的点的运输总量分别增加插入边权值*对方的集合点数。相当于是把一个大集合不断分割的过程,最后可以得到每个点的运输总量。但是在实现过程当中发现集合的分割不好实现。
这时候想到反其道行之,将边从大到小排序再插入,那么每个点刚开始都是自成一个集合,然后不断合并,就是一个并查集。这里要用到两个并查集,一个是用来记录合并过程当中已合并的集合,另一个则是用来记录运输量的增量。当然,别人有比我思路更简洁的方法,这只是记录一下我在当时的思路而已。
</pre><p></p><pre name="code" class="cpp"><pre name="code" class="cpp">#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int pre[401000],n,cnt,no[401000],siz[401000],p[401000];
long long addv[401000];
typedef struct node node;
struct node
{
int from,to,w;
}edge[201000];
int find_ds(int a){
return a==pre[a]?a:pre[a]=find_ds(pre[a]);
}
int find_ps(int a){
return a==p[a]?a:p[a]=find_ps(p[a]);
}
long long find_p(int a){
if(p[a]==a){
return addv[a];
}
else{
addv[a]+=find_p(p[a]);
find_ps(a);
return addv[a];
}
}
int cmp(int a,int b){
return edge[a].w>edge[b].w;
}
int main(){
int a,b,c;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n-1;i++){
scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].w);
}
for(int i=1;i<=2*n+10;i++){
no[i]=i;
pre[i]=i;
p[i]=i;
siz[i]=1;
addv[i]=0;
}
no[0]=0;
sort(no,no+n-1,cmp);
int f,t,id;
int cntt=0;
for(int i=0;i<n-1;i++){
id=no[i];
t=find_ds(edge[id].to);
f=find_ds(edge[id].from);
addv[f]+=(long long)edge[id].w*siz[t];
addv[t]+=(long long)edge[id].w*siz[f];
cntt++;
pre[f]=cntt+n;
pre[t]=cntt+n;
p[t]=cntt+n;
p[f]=cntt+n;
siz[cntt+n]=siz[f]+siz[t];
}
long long ans=0;
for(int i=1;i<=n;i++){
if(ans<find_p(i)){
ans=find_p(i);
}
}
printf("%lld\n",ans);
}
return 0;
}