题意:给出一棵树,找出一个点,求出所有点到这个点的权值和最大,权值为路径上所有边权的最小值。
用神奇的并查集,把路按照权值从大到小排序,然后用类似Kruskal的方法不断的加入边。 对于要加入的一条路,这条路连接这城市x和y,x所在的集合为A, y所在的集合为B, 可以确定A,B集合内的所有路都比当前这条路的权值大。如果让集合B加入集合A,就是让中心城市位于集合A,那么可以确定这两个集合合并之后的总权值为: A的权值总和+B的数量*当前这条路的权值。同样算出让集合B加入集合A的情况,取两者合并后权值大的进行合并。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 const double eps=1e-5; 11 #define cl(a) memset(a,0,sizeof(a)) 12 #define ts printf("***** "); 13 const int MAXN=200005; 14 int n,m,tt; 15 int F[MAXN]; 16 struct Edge 17 { 18 int a,b,c; 19 void input() 20 { 21 scanf("%d%d%d",&a,&b,&c); 22 } 23 }edge[MAXN]; 24 int find(int x) 25 { 26 if(F[x]==-1) return x; 27 return F[x]=find(F[x]); 28 } 29 struct Node 30 { 31 long long sum; 32 long long num; 33 }node[MAXN]; 34 bool cmp(Edge a,Edge b) 35 { 36 return a.c>b.c; 37 } 38 int main() 39 { 40 int i,j,k; 41 #ifndef ONLINE_JUDGE 42 freopen("1.in","r",stdin); 43 #endif 44 while(scanf("%d",&n)!=EOF) 45 { 46 for(i=1;i<n;i++) edge[i].input(); 47 sort(edge+1,edge+n,cmp); 48 for(i=1;i<=n;i++) 49 { 50 node[i].num=1; 51 node[i].sum=0; 52 F[i]=-1; 53 } 54 for(i=1;i<n;i++) 55 { 56 int a1=edge[i].a; 57 int a2=edge[i].b; 58 int t1=find(a1); 59 int t2=find(a2); 60 if(node[t1].sum+(long long)node[t2].num*edge[i].c<node[t2].sum+(long long)node[t1].num*edge[i].c) 61 { 62 F[t1]=t2; //t2作为被选择的点 63 node[t2].num+=node[t1].num; 64 node[t2].sum+=(long long)edge[i].c*node[t1].num; 65 } 66 else 67 { 68 F[t2]=t1; 69 node[t1].num+=node[t2].num; 70 node[t1].sum+=(long long)edge[i].c*node[t2].num; 71 } 72 } 73 printf("%lld ",node[find(1)].sum); 74 } 75 }