2012 Asia ChangChun Regional Contest - E. Conquer a New Region

算法提示

并查集

 

题目大意

有 n 个城镇,编号为 1 - n ,有 n - 1 条路将它们联通,任何两个城镇之间有唯一的一条路径,每条路有它们的各自的通行量,从一个城镇到另一个城镇的通行量路径上的最小的那个量(如1 2 2,2 3 1,则 1 到 3 的最大通行量为 1)。现在需要找一个中心城市,使这个城市到其他各个城市的通行量之和最大。 

 

做法分析

令 sum[i] 表示 i 结点所在联通块中通行量之和的最大值,cnt[i] 表示 i 结点所在联通块中的结点数。

我们首先考虑在这棵树中,对于一条边权最小的边 ( u , v , d ),断开这条边可以得到 u 子树和 v 子树,那么所求答案为 max{ sum[u] + cnt[v] * d , sum[v] + cnt[u] * d },而式子中 sum[u] 和 sum[v] 又是重复子问题。

于是我们将边权从大到小排序,每次连接两棵子树,并算出新子树的最大值 sum,并维护新子树的结点数 cnt 。

 

参考代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 #define MAXN 200010
 8 #define MAX(a,b) (a>b?a:b)
 9 typedef long long LL;
10 
11 int n,f[MAXN],cnt[MAXN];
12 LL sum[MAXN];
13 
14 struct node
15 {
16     int u,v,d;
17     bool operator<(const node &x) const{
18         return d>x.d;
19     }
20 }e[MAXN];
21 
22 void Init()
23 {
24     memset(f,0,sizeof(f));
25     memset(sum,0,sizeof(sum));
26     int i;
27     for(i=1;i<n;++i)
28         scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].d);
29     for(i=1;i<=n;++i) cnt[i]=1;
30     sort(e+1,e+n);
31 }
32 
33 int Find(int u)
34 {
35     return f[u]?f[u]=Find(f[u]):u;
36 }
37 
38 void Work()
39 {
40     int i,fu,fv;
41     for(i=1;i<n;++i){
42         fu=Find(e[i].u); fv=Find(e[i].v);
43         sum[fu]=MAX((1LL*cnt[fu]*e[i].d+sum[fv]),(1LL*cnt[fv]*e[i].d+sum[fu]));
44         f[fv]=fu; cnt[fu]+=cnt[fv];
45     }
46     printf("%I64d\n",sum[fu]);
47 }
48 
49 int main()
50 {
51     while(~scanf("%d",&n)){
52         Init();
53         Work();
54     }
55     return 0;
56 }
View Code

 

题目链接

2012 Asia ChangChun Regional Contest - E. Conquer a New Region

posted @ 2015-10-19 22:42  Orenji.Sora  Views(154)  Comments(0)    收藏  举报