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;
}