码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ 1827】 [Usaco2010 Mar]gather 奶牛大集会

时间:2015-03-17 15:56:36      阅读:126      评论:0      收藏:0      [点我收藏+]

标签:bzoj   oi   思路题   dfs   

1827: [Usaco2010 Mar]gather 奶牛大集会

Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 722  Solved: 314
[Submit][Status][Discuss]

Description

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

Sample Output

15

HINT

Source


思路题。


发现这些农场构成了一棵树。


所以首先以任意一个点为根建树,并把这个点当做目标点。


那么最终的答案就是每条树边乘有几头牛要走,一条边有几头牛要走其实就是这条边下面有几个子孙。


于是我们预处理出以1为根的树的答案,并求出每个节点有几个子孙,然后O(1)转移到他的儿子的答案,这个儿子又可以O(1)转移到他自己的儿子。。。


因此我们用O(n)时间就求出以每个点为目的地的路程和,输出最小即可。


转移方法是:

根变成儿子的时候,只有连接儿子的边要变化,根据预处理出的每个节点的儿子,即可转移。


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define M 200000+5
#define LL long long
using namespace std;
int tot=0,h[M],n,c[M],cnt;
LL ans;
struct edge
{
	int y,ne;
	LL v;
}e[M*2];
struct data
{
	int son;
	LL l;
}a[M];
void Addedge(int x,int y,LL l)
{
	e[++tot].y=y;
	e[tot].ne=h[x];
	e[tot].v=l;
	h[x]=tot;
}
void Prepare(int x,int fa)
{
	for (int i=h[x];i;i=e[i].ne)
	{
		int y=e[i].y;
		if (y==fa) continue;
		Prepare(y,x);
		a[x].son+=a[y].son;
		a[x].l=a[x].l+a[y].l+(1LL*e[i].v*a[y].son);
	}
	a[x].son+=c[x];
}
void dfs(int x,int fa,LL now)
{
	for (int i=h[x];i;i=e[i].ne)
	{
		int y=e[i].y;
		if (y==fa) continue;
		LL k=now+1LL*e[i].v*(cnt-a[y].son*2);
		ans=min(ans,k);
		dfs(y,x,k);
	}
}
int main()
{
        scanf("%d",&n);
	cnt=0;
	for (int i=1;i<=n;i++)
		scanf("%d",&c[i]),cnt+=c[i];
	for (int i=1;i<n;i++)
	{
		int x,y;
		LL l;
		scanf("%d%d%lld",&x,&y,&l);
		Addedge(x,y,l);
		Addedge(y,x,l);
	}
	Prepare(1,0);
	ans=a[1].l;
	dfs(1,0,a[1].l);
	cout<<ans<<endl;
	return 0;
}

技术分享

【BZOJ 1827】 [Usaco2010 Mar]gather 奶牛大集会

标签:bzoj   oi   思路题   dfs   

原文地址:http://blog.csdn.net/regina8023/article/details/44341749

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!