HDU

来源:互联网 发布:谷歌读屏软件下载5.02 编辑:程序博客网 时间:2024/05/22 00:23

题目链接


题意:

给n个城镇,然后每两个城镇的价值给出,但是u->v的价值是u->v这条路径上的最小值,问从任意一个点出发到其他位置的和的最大值

思路:

很好的一个并查集题目,和队友想了一会才想出来.说实话这个并查集不是很好想。

因为这个题目是路径上的最小值为sij,所以我们要将边的权值从大到小排序,这样在用并查集维护两堆合并的最优值时,假设祖先分别为f1和f2,首先内部我们已经处理好了(每次合并就已经处理好),因为从大到小排序的,那么我们现在维护的这条边一定是当前最小的,那么我们以祖先f1到另一堆的所有点的sij即为当前这条边的cij,而到自己这一堆我们的已经处理好了为sum[f1]。(以f2同理)

关键是合并的时候怎么合并,因为要求和的最大值,所以这里我们用num[i]表示该堆的点的个数,sum[i]表示该堆,以i为选定的点,到本堆其他点的和的最大值是多少,合并时 f1,f2两堆,如果num[f2]*w+sum[f1]大,则新堆以f1为选定点,如果num[f1]*w+sum[f2]大则合并到f2上,这个过程中维护一个最大值即可》

#include<bits/stdc++.h>using namespace std;const int maxn = 2e5+5;typedef long long ll;int n;int pre[maxn],num[maxn];ll sum[maxn],ans;void init(){for(int i = 0;i <= n;++i)pre[i] = i,sum[i] = 0,num[i] = 1;}struct node{int u,v,w;bool operator<(const node & z) const{return w > z.w;}}a[maxn];int find(int x){return x == pre[x] ? x : pre[x] = find(pre[x]);}void join(int x,int y,int w){int f1 = find(x),f2 = find(y);ll s1 = sum[f1] + (ll) w * num[f2];ll s2 = sum[f2] + (ll) w * num[f1];if(s1 >= s2){pre[f2] = f1;sum[f1] = s1;num[f1] += num[f2];}else{pre[f1] = f2;sum[f2] = s2;num[f2] += num[f1];}ans = max(ans,max(sum[f1],sum[f2]));return ;}int main(){while(~scanf("%d",&n)){init();for(int i = 1;i < n;++i)scanf("%d %d %d",&a[i].u,&a[i].v,&a[i].w);sort(a+1,a+n);ans = 0;for(int i = 1;i < n;++i){join(a[i].u,a[i].v,a[i].w);}printf("%lld\n",ans);}return 0;}



原创粉丝点击