51NOD 1424 零树(树形DP)

基准时间限制:1 秒 空间限制:131072 KB

有一棵以1为根的树,他有n个结点,用1到n编号。第i号点有一个值vi。

现在可以对树进行如下操作:

步骤1:在树中选一个连通块,这个连通块必须包含1这个结点。

步骤2:然后对这个连通块中所有结点的值加1或者减1。

问最少要经过几次操作才能把树中所有结点都变成0。

注意:步骤1与步骤2合在一起为一次操作。

Input
单组测试数据。
第一行有一个整数n(1 ≤ n ≤ 10^5)
接下来n-1行,每行给出 ai 和 bi (1 ≤ ai, bi ≤ n; ai ≠ bi),表示ai和bi之间有一条边,输入保证是一棵树。
最后一行有n个以空格分开的整数,表示n个结点的值v1, v2, ..., vn (|vi| ≤ 10^9)。
Output
输出一个整数表示最少的操作步数。.
Input示例
3
1 2
1 3
1 -1 1
Output示例
3

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <vector>

using namespace std;

const int MAXN = 100005;

long long dp[MAXN][2];
vector<int>edge[MAXN];	//邻接表 
long long values[MAXN];  //存放每个点的值 

void BFS(int now,int father){
	for(int i=0 ; i<edge[now].size() ; i++){
		if(edge[now][i] == father)continue;
		BFS(edge[now][i],now);
		dp[now][0] = max(dp[edge[now][i]][0],dp[now][0]);
		dp[now][1] = max(dp[edge[now][i]][1],dp[now][1]); 
	}
	long long mid = values[now]+dp[now][1]-dp[now][0];
	/*前面专门开一个数组values存放值就是为了方便这里*/
	dp[now][mid<0] += abs(mid);
}

int main(){

	int N;
	cin>>N;
	memset(dp,0,sizeof(dp));
	memset(values,0,sizeof(values));
	for(int i=1 ; i<N ; i++){
		int A,B;
		scanf("%d %d",&A,&B);
		edge[A].push_back(B);/*一般都建成无向图以防有坑*/
		edge[B].push_back(A);
	}
	for(int i=1 ; i<=N ; i++){
		scanf("%lld",&values[i]);
	}
	BFS(1,-1);
	cout<<dp[1][0] + dp[1][1]<<endl;
	
	return 0;
}
 

猜你喜欢

转载自blog.csdn.net/vocaloid01/article/details/79931283