1737 配对
基准时间限制:1 秒 空间限制:131072 KB 分值: 40
难度:4级算法题
收藏
关注
给出一棵n个点的树,将这n个点两两配对,求所有可行的方案中配对两点间的距离的总和最大为多少。
Input
一个数n(1<=n<=100,000,n保证为偶数) 接下来n-1行每行三个数x,y,z表示有一条长度为z的边连接x和y(0<=z<=1,000,000,000)
Output
一个数表示答案
Input示例
6 1 2 1 1 3 1 1 4 1 3 5 1 4 6 1
Output示例
7 //配对方案为(1,2)(3,4)(5,6)
考虑每一条边被统计进答案几次。
代码
若断开这条边后树形成大小为s1、s2的两个联通块则这条边最多被统计min(s1,s2)次。
构造方案的做法为:找出树的重心,让所有n/2条路径都经过重心即可(只要保证删去重心后任意同一联通块中的两点不构成路径即可,因为是重心,所以这是很好构造的)
这样构造出来的配对方案满足了每条边都没被统计min(s1,s2)次,所以这道题只要求出断开每条边后两个联通块的大小即可。
时间复杂度O(n)
1 #include <cstdio> 2 #include <cctype> 3 #include <vector> 4 5 typedef long long LL; 6 const int MAXN=100010; 7 8 int n; 9 10 LL ans; 11 12 int son[MAXN]; 13 14 struct node { 15 int to,val; 16 node() {} 17 node(int to,int val):to(to),val(val) {} 18 }; 19 20 std::vector<node> Graph[MAXN]; 21 22 inline void read(int&x) { 23 int f=1;register char c=getchar(); 24 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 25 for(;isdigit(c);x=x*10+c-48,c=getchar()); 26 x=x*f; 27 } 28 29 void DFS(int now,int fa) { 30 son[now]=1; 31 for(register int i=0;i<Graph[now].size();++i) { 32 node p=Graph[now][i]; 33 if(p.to==fa) continue; 34 DFS(p.to,now); 35 son[now]+=son[p.to]; 36 } 37 return; 38 } 39 40 void DFS_Ans(int now,int fa) { 41 for(register int i=0;i<Graph[now].size();++i) { 42 node p=Graph[now][i]; 43 if(p.to==fa) continue; 44 DFS_Ans(p.to,now); 45 ans+=(LL)(son[p.to]<n-son[p.to]?son[p.to]:(n-son[p.to]))*p.val; 46 } 47 return; 48 } 49 50 int hh() { 51 read(n); 52 for(register int x,y,z,i=1;i<n;++i) { 53 read(x);read(y);read(z); 54 Graph[y].push_back(node(x,z)); 55 Graph[x].push_back(node(y,z)); 56 } 57 DFS(1,0); 58 DFS_Ans(1,0); 59 printf("%lld\n",ans); 60 return 0; 61 } 62 63 int sb=hh(); 64 int main(int argc,char**argv) {;}