HDU
来源:互联网 发布:seo点击软件 编辑:程序博客网 时间:2024/05/29 17:20
思路:类似Kruskal算法,将边按权值从大到小排序,每次加入一条边AB,如果以A所在的集合为中心城市,那么总权值为A所在集合的权值加上B所在集合点的数量乘以这条边的权值,因为A、B所在集合中的边肯定大于AB的权值,如果B所在的集合为中心城市,可以以同样的方法计算,取两者中大的那一个。
#include<cstdio>#include<set>#include<algorithm>#include<cstring>#include<iostream>#include<map>#include<queue>#include<vector>#include<stack>#include<string>#include<sstream>#include<set>#include<cmath>using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 2e5 + 20;const double EPS = 1e-5;const int mod = 1e9 + 7;typedef unsigned long long ull;typedef long long LL;int dx[] = {0, 0, -1, 1, -1, -1, 1, 1};int dy[] = {1, -1, 0, 0, -1, 1, -1, 1};struct Edge{ int from, to, c; bool operator <(const Edge& rhs) const{ return c > rhs.c; }}a[maxn];struct Node{ LL sum; int num;}b[maxn];int f[maxn];int Find(int x){ return x == f[x] ? x : f[x] = Find(f[x]);}int main(){ int n; while(scanf("%d", &n) == 1){ for(int i = 0; i < n - 1; ++i){ scanf("%d%d%d", &a[i].from, &a[i].to, &a[i].c); } sort(a, a + n - 1); for(int i = 1; i <= n; ++i) f[i] = i; for(int i = 1; i <= n; ++i){ b[i].num = 1; b[i].sum = 0; } for(int i = 0; i < n - 1; ++i){ int t1 = Find(a[i].from), t2 = Find(a[i].to); if(b[t1].sum + (LL)b[t2].num * (LL)a[i].c > b[t2].sum + (LL)b[t1].num * (LL)a[i].c){ f[t2] = t1; b[t1].num += b[t2].num; b[t1].sum = b[t1].sum + (LL)b[t2].num * (LL)a[i].c; } else{ f[t1] = t2; b[t2].num += b[t1].num; b[t2].sum = b[t2].sum + (LL)b[t1].num * (LL)a[i].c; } } printf("%lld\n", b[Find(1)].sum); }}/*3 33 1 23 2 02 3 2*/