基准时间限制: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; }