首页 > 技术文章 > [Usaco2010 Mar]gather 奶牛大集会

hzoi-mafia 2017-10-09 12:21 原文

[Usaco2010 Mar]gather 奶牛大集会

题目

Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。每个奶牛居住在 N(1<=N<=100,000) 个农场中的一个,这些农场由N-1条道路连接,并且从任意一个农场都能够到达另外一个农场。道路i连接农场A_i和B_i(1 <= A_i <=N; 1 <= B_i <= N),长度为L_i(1 <= L_i <= 1,000)。集会可以在N个农场中的任意一个举行。另外,每个牛棚中居住者C_i(0 <= C_i <= 1,000)只奶牛。在选择集会的地点的时候,Bessie希望最大化方便的程度(也就是最小化不方便程度)。比如选择第X个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和,(比如,农场i到达农场X的距离是20,那么总路程就是C_i*20)。帮助Bessie找出最方便的地点来举行大集会。 考虑一个由五个农场组成的国家,分别由长度各异的道路连接起来。在所有农场中,3号和4号没有奶牛居住。 

INPUT

第一行:一个整数N * 第二到N+1行:第i+1行有一个整数C_i * 第N+2行到2*N行,第i+N+1行为3个整数:A_i,B_i和L_i。

OUTPUT

第一行:一个值,表示最小的不方便值。

SAMPLE

INPUT

5
1
1
0
0
2
1 3 1
2 3 2
3 4 3
4 5 3

OUTPUT

15

解题报告

这破水题水了我一上午

树规

显然我们需要找出一个根来先算出一个不那么优的解,再去更新其他的解

第一步很容易,第二步也很容易(我tm卡了一个上午)

设目前的答案为$ans$,儿子节点的答案为$next$

$$next=ans-size_{son}\times w_{i}+(tot-size_{son})\times w_{i}$$

显然我们可以用高深的数学知识乘法分配率把式子化简成这样:

$$next=ans+(tot-2\times size_{son})\times w_{i}$$

那么我们使$tot<2\times size_{son}$,后面的式子就是负的,$ans$就被更新得更小了

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 inline int read(){
 6     int sum(0);
 7     char ch(getchar());
 8     for(;ch<'0'||ch>'9';ch=getchar());
 9     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
10     return sum;
11 }
12 struct edge{
13     int e,w;
14     edge *n;
15 }a[200005],*pre[100005];
16 int tot;
17 inline void insert(int s,int e,int w){
18     a[++tot].e=e;
19     a[tot].w=w;
20     a[tot].n=pre[s];
21     pre[s]=&a[tot];
22 }
23 typedef long long L;
24 int n;
25 L c[100005],size[100005],dis[100005];
26 L ans,sum;
27 inline L dfs(int u,int fa){
28     size[u]=c[u];
29     L ret(dis[u]*c[u]);
30     for(edge *i=pre[u];i;i=i->n){
31         int e(i->e);
32         if(e==fa)continue;
33         dis[e]=dis[u]+i->w;
34         ret+=dfs(e,u);
35         size[u]+=size[e];
36     }
37     return ret;
38 }
39 inline void cal(int u,int fa){
40     for(edge *i=pre[u];i;i=i->n){
41         int e(i->e);
42         if(e==fa)continue;
43         if(sum<size[e]<<1){
44             ans+=(sum-(size[e]<<1))*i->w;
45             cal(e,u);
46         }
47     }
48 }
49 int main(){
50     memset(pre,NULL,sizeof(pre));
51     n=read();
52     for(int i=1;i<=n;++i)
53         c[i]=read();
54     for(int i=1;i<n;++i){
55         int x(read()),y(read()),z(read());
56         insert(x,y,z),insert(y,x,z);
57     }
58     ans=dfs(1,0);
59     sum=size[1];
60     cal(1,0);
61     printf("%lld",ans);
62 }
View Code

 

推荐阅读