【问题描述】
azui大爷厌倦了每天在家颓废的生活,于是开始打工送快递。Jeremy同学不想让azui大爷太轻松,于是想让他送快递的路程尽可能的长。
一句话来说就是:
给出一棵n个点的树,将这n个点两两配对,求所有可行的方案中配对两点间的距离的总和最大为多少。
【输入格式】
一个数n(1<=n<=100,000,n保证为偶数)
接下来n-1行每行三个数x,y,z表示有一条长度为z的边连接x和y(0<=z<=1,000,000,000)
【输出格式】
一个数表示答案。
【样例输入】
6
1 2 1
1 3 1
1 4 1
3 5 1
4 6 1
【样例输出】
7
【样例解释】
(1,2)(3,4)(5,6)分别配对
【数据范围】
对于20%的数据,n <= 14
对于另20%的数据,所给的树是一条链。
对于100%的数据,n <= 100000
#include<iostream> #include<cstdio> using namespace std; typedef long long LL; const int N=1e5+5; int n, fa[N], fir[N], ecnt; struct node{ int e, w, next; }edge[N<<1]; LL ans, pcnt[N]; void Getin( int &shu ) { char c; int f=1; shu=0; for( c=getchar(); c<'0' || c>'9'; c=getchar() ) if( c=='-' ) f=-1; for( ; c>='0' && c<='9'; c=getchar() ) shu=shu*10+c-'0'; shu*=f; } void Link( int s, int e, int w ) { edge[ ++ecnt ].e=e; edge[ecnt].w=w; edge[ecnt].next=fir[s]; fir[s]=ecnt; edge[ ++ecnt ].e=s; edge[ecnt].w=w; edge[ecnt].next=fir[e]; fir[e]=ecnt; } void Dfs( int s ) { pcnt[s]=1; for( int i=fir[s]; i; i=edge[i].next ) if( edge[i].e!=fa[s] ){ fa[ edge[i].e ]=s; Dfs( edge[i].e ); pcnt[s]+=pcnt[ edge[i].e ]; } } int main() { Getin(n); for( int i=1; i<n; i++ ) { int a, b, c; Getin(a); Getin(b); Getin(c); Link( a, b, c ); } Dfs(1); for( int s=1; s<=n; s++ ) for( int i=fir[s]; i; i=edge[i].next ) if( fa[ edge[i].e ]==s ) ans+=min( pcnt[ edge[i].e ], n-pcnt[ edge[i].e ] )*edge[i].w; printf( "%lld\n", ans ); return 0; } /* 一条边断开后图被分为s1, s2两部分 用边的权值乘上min(s1,s2)即是答案 */