hdu 4424 Conquer a New Region
唉,这题的思路果断没想到啊。
题意:给定一棵树,定义两点间的权值 为 这条路上最小的边权值,求一个中心点,使得它到其他点的权值最大。
采用贪心策略,把权值从大到小排序,每条边的两个顶点属于两个集合,而这条边就是连同两个集合的必经之路。
并且因为是降序,所以要从一个集合的某个点到达另一个集合的某个点的权值一定就是这条边的权值。
我们保存两个集合的点的数目,每次比较选哪个集合里的点作为中心点比较好。
并查集维护。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; #define N 200005 struct node { int s,e; int w; }ed[N]; int set[N],num[N]; long long sum[N]; bool cmp(const node &aa,const node &bb) { return aa.w>bb.w; } void init(int n) { for(int i=1;i<=n;i++) set[i]=i,num[i]=1,sum[i]=0; } inline int find(int x) { int i,j,r = x; while (set[r] != r) r = set[r]; i = x; while (i != r) { j = set[i]; set[i] = r; i = j; } return r; } inline void merge(int a,long long x,int b,long long y) { if(x>y) set[b]=a,sum[a]=x,num[a]+=num[b]; else set[a]=b,sum[b]=y,num[b]+=num[a]; } inline int ReadInt() { char ch = getchar(); int data = 0; while (ch < '0' || ch > '9') { ch = getchar(); } do { data = data*10 + ch-'0'; ch = getchar(); }while (ch >= '0' && ch <= '9'); return data; } int main() { int n; while(~scanf("%d",&n)) { for(int i=0;i<n-1;i++) ed[i].s=ReadInt(),ed[i].e=ReadInt(),ed[i].w=ReadInt(); init(n); sort(ed,ed+n-1,cmp); for(int i=0;i<n-1;i++) { int s=find(ed[i].s); int e=find(ed[i].e); if(s==e) continue; long long x=sum[s]+num[e]*ed[i].w; //中心点在s集合 long long y=sum[e]+num[s]*ed[i].w; //中心点在e集合 merge(s,x,e,y); } printf("%I64d\n",sum[find(1)]); } return 0; }
开了输入挂后排到第一了,可惜算法不是自己想的……