【BZOJ】1827: [Usaco2010 Mar]gather 奶牛大集会(树形dp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1827

仔细想想就好了,,

每个点维护两个值,一个是子树的费用,一个是除了子树和自己的费用。都可以用dfs做。

维护第一个就是简单的dp。d1[i]=sum{d1[j]+w(i, j)*son1[j]},j是i的子女

第二个就有些麻烦,因为要考虑的不只是这个点的父亲,还要考虑这个点父亲的子树。

那么

d2[i]=d2[fa]+w(fa, i)*son1[i]+d1[fa]-d1[i]

而在处理这些方程有一些细节,不一定完全和上边的的方程一样,具体看代码

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

using namespace std;

typedef long long ll;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%lld", a)

#define dbg(x) cout << (#x) << " = " << (x) << endl

#define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }

#define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }

inline const int max(const int &a, const int &b) { return a>b?a:b; }

inline const ll min(const ll &a, const ll &b) { return a<b?a:b; }



const int N=100005;

int ihead[N], cnt, n;

struct ED { int to, next; ll w; }e[N<<1];

ll d[N][2], ans=~0ull>>1, c[N], son[N][2];

void add(int u, int v, ll w) {

	e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].w=w;

	e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; e[cnt].w=w;

}

void dfs1(int x, int fa) {

	int y;

	for(int i=ihead[x]; i; i=e[i].next) if((y=e[i].to)!=fa) {

		ll w=e[i].w;

		dfs1(y, x);

		son[x][0]+=son[y][0]+c[y];

		d[x][0]+=d[y][0]+w*(son[y][0]+c[y]);

	}

}

void dfs2(int x, int fa) {

	int y;

	for(int i=ihead[x]; i; i=e[i].next) if((y=e[i].to)!=fa) {

		ll w=e[i].w;

		son[y][1]=son[x][1]+c[x]+son[x][0]-son[y][0]-c[y];

		d[y][1]=d[x][1]+w*son[y][1]+d[x][0]-d[y][0]-w*(son[y][0]+c[y]);

		dfs2(y, x);

	}

}

int main() {

	read(n);

	for1(i, 1, n) read(c[i]);

	rep(i, n-1) { int u=getint(), v=getint(), w=getint(); add(u, v, w); }

	dfs1(1, 0); dfs2(1, 0);

	for1(i, 1, n) ans=min(ans, d[i][0]+d[i][1]);

	print(ans);

	return 0;

}

 

 


 

 

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号没有奶牛居住。 【BZOJ】1827: [Usaco2010 Mar]gather 奶牛大集会(树形dp)

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

你可能感兴趣的:(USACO)