首页 > 技术文章 > zoj 3659 Conquer a New Region The 2012 ACM-ICPC Asia Changchun Regional Contest

code-painter 2014-10-05 20:25 原文

Conquer a New Region

Time Limit: 5 Seconds      Memory Limit: 32768 KB

The wheel of the history rolling forward, our king conquered a new region in a distant continent.

There are N towns (numbered from 1 to N) in this region connected by several roads. It's confirmed that there is exact one route between any two towns. Traffic is important while controlled colonies are far away from the local country. We define the capacity C(i, j) of a road indicating it is allowed to transport at most C(i, j) goods between town i and town j if there is a road between them. And for a route between i and j, we define a value S(i, j) indicating the maximum traffic capacity between i and j which is equal to the minimum capacity of the roads on the route.

Our king wants to select a center town to restore his war-resources in which the total traffic capacities from the center to the other N - 1 towns is maximized. Now, you, the best programmer in the kingdom, should help our king to select this center.

Input

There are multiple test cases.

The first line of each case contains an integer N. (1 ≤ N ≤ 200,000)

The next N - 1 lines each contains three integers a, b, c indicating there is a road between town a and town b whose capacity is c. (1 ≤ a, b ≤ N, 1 ≤ c ≤ 100,000)

Output

For each test case, output an integer indicating the total traffic capacity of the chosen center town.

Sample Input

4
1 2 2
2 4 1
2 3 1
4
1 2 1
2 4 1
2 3 1

Sample Output

4
3

Contest: The 2012 ACM-ICPC Asia Changchun Regional Contest

 

题意:给你一棵树,s[i,j]表示从i点到j点的路径权值的最小值,f[i]表示i点到树上除i外所有的点j的s[i,j]。求最大的f[i]是多少。

思路1:先把所有边按从大到小排序。一条边一条边地加入树中,每次合并两个集合(其实就是两个并查集,也就是两棵树),f[i]表示以i为根的这棵子树每个节点都能获得比原来多f[i]的值。不断合并两个集合,然后用类似并查集压缩路径的方法压缩f[i]。最后就能得到所有f[i]的值,再从中选一个最大的,即答案。

 1 /*
 2  * Author:  Joshua
 3  * Created Time:  2014年10月05日 星期日 10时01分55秒
 4  * File Name: e.cpp
 5  */
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<algorithm>
 9 #include<iostream>
10 using namespace std;
11 #define maxn 200001
12 typedef long long LL;
13 int n;
14 struct edge
15 {
16     int u,v,w;
17     bool operator < (const edge& p) const
18     {
19         return w>p.w;
20     }
21     void input()
22     {
23         scanf("%d%d%d",&u,&v,&w);
24     }
25 } e[maxn];
26 
27 int fa[maxn],size[maxn];
28 bool vis[maxn];
29 LL f[maxn];
30 void init()
31 {
32     for (int i=1;i<n;++i)
33         e[i].input();
34     sort(e+1,e+n);
35     for (int i=1;i<=n;++i)
36     {
37         fa[i]=i;
38         size[i]=1;
39     }
40     memset(f,0,(n+1)<<3);
41     memset(vis,0,n+1);
42 }
43 
44 int gf(int x,int t)
45 {
46     if (vis[x]) return f[x];
47     if (t) vis[x]=true;
48     if (fa[x]==x) return x;
49     int temp,tf=fa[x];
50     temp=gf(tf,t);
51     if (!t)
52     {
53         if (temp!=tf) f[x]+=f[tf];
54     }
55     else f[x]+=f[tf];
56     return fa[x]=temp;
57 }
58 
59 void solve()
60 {
61     int u,v,fu,fv;
62     LL ans=0,w;
63     for (int i=1;i<n;++i)
64     {
65         u=e[i].u; v=e[i].v; w=e[i].w;
66         fu=gf(u,0);
67         fv=gf(v,0);
68         f[fu]+=size[fv]*w;
69         f[fv]+=(size[fu]*w-f[fu]);
70         size[fu]+=size[fv];
71         fa[fv]=fu;
72     }
73     for (int i=1;i<=n;++i)
74     {
75         if (!vis[i]) u=gf(i,1);
76         ans=max(ans,f[i]);
77     }
78     cout<<ans<<endl;
79 }
80         
81 int main()
82 {
83     while (scanf("%d",&n)!=EOF)
84     {
85         init();
86         solve();
87     }
88     return 0;
89 }

思路2:类似于思路1,但既然我们只要求一个最大的,那么其他的值求出来就很浪费了。因此我们将思路1中的f[i]改为以i为根的并查集中,当前获得的最大值的那个点的值。因为在不断合并中,这个并查集中的每个点获得的数值都是一样的,所以当前最大的那个点肯定在最后也是最大的。因此我们做的就是每次合并两个集合,选出一个最大的。然后不断合并即可。最后的答案肯定能在最后一次合并中找出。

 1 /*
 2  * Author:  Joshua
 3  * Created Time:  2014年10月05日 星期日 20时01分10秒
 4  * File Name: e.cpp
 5  */
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<algorithm>
 9 #include<iostream>
10 using namespace std;
11 #define maxn 200001
12 typedef long long LL;
13 int n;
14 struct edge
15 {
16     int u,v,w;
17     bool operator < (const edge& p) const
18     {
19         return w>p.w;
20     }
21     void input()
22     {
23         scanf("%d%d%d",&u,&v,&w);
24     }
25 } e[maxn];
26 
27 int fa[maxn],size[maxn];
28 LL f[maxn];
29 void init()
30 {
31     for (int i=1;i<n;++i)
32         e[i].input();
33     sort(e+1,e+n);
34     for (int i=1;i<=n;++i)
35     {
36         fa[i]=i;
37         size[i]=1;
38     }
39     memset(f,0,(n+1)<<3);
40 }
41 
42 int gf(int x)
43 {
44     int &t=fa[x];
45     return t= ( t==x ? x:gf(t));
46 }
47 
48 void solve()
49 {
50     int u,v,fu,fv;
51     LL ans=0,w,tu,tv;
52     for (int i=1;i<n;++i)
53     {
54         u=e[i].u; v=e[i].v; w=e[i].w;
55         fu=gf(u);
56         fv=gf(v);
57         tu=f[fu]+size[fv]*w;
58         tv=f[fv]+size[fu]*w;
59         if (tu>tv)
60         {
61             fa[fv]=fu;
62             size[fu]+=size[fv];
63             f[fu]=tu;
64         }
65         else
66         {
67             fa[fu]=fv;
68             size[fv]+=size[fu];
69             f[fv]=tv;
70         }
71     }
72     ans=max(tu,tv);
73     cout<<ans<<endl;
74 }
75         
76 int main()
77 {
78     while (scanf("%d",&n)!=EOF)
79     {
80         init();
81         solve();
82     }
83     return 0;
84 }

 

推荐阅读