题目链接:http://codeforces.com/contest/1092/problem/F
解题心得:题意很简答就不多说了。仔细观察可以发现如果知道了一个点作为 V V V点得到的答案,那么当转移到它的儿子节点时可以直接 O ( 1 ) O(1) O(1)得到。具体转移是这样的,先随便选择一个点作为根节点,记为 r o o t root root。预处理出从根节点开始每个节点为子树时根节点时的权值和记为 s u m [ i ] sum[i] sum[i]。转移方程也很简单,假设已经得到了 V V V点的答案,转移到 V V V的儿子 u u u那么可以这样转移 d p [ u ] = d p [ V ] + ( s u m [ r o o t ] − s u m [ u ] ) − s u m [ u ] dp[u] = dp[V] + (sum[root] - sum[u]) - sum[u] dp[u]=dp[V]+(sum[root]−sum[u])−sum[u]。其实就是一个很简单的树上dp。
#include <bits/stdc++.h>
using namespace std;
typedef complex<double> cp;
typedef long long ll;
const ll maxn = 2e5+100;
const double pi = acos(-1);
ll n, num[maxn], dp[maxn], sum[maxn];
vector <int> ve[maxn];
void init() {
scanf("%lld", &n);
for(int i=1;i<=n;i++) scanf("%lld", &num[i]);
for(int i=1;i<n;i++) {
int a, b; scanf("%d%d", &a, &b);
ve[a].push_back(b);
ve[b].push_back(a);
}
}
ll dfs1(int pre, int now, ll deep) {
ll Sum = num[now]*deep;
for(int i=0;i<ve[now].size();i++) {
int v = ve[now][i];
if(v == pre) continue;
Sum += dfs1(now, v, deep+1);
}
return Sum;
}
ll dfs2(int pre, int now) {
sum[now] = num[now];
for(int i=0;i<ve[now].size();i++) {
int v = ve[now][i];
if(v == pre) continue;
sum[now] += dfs2(now, v);
}
return sum[now];
}
void DP(int pre, int now) {
if(pre != -1) {
dp[now] = dp[pre] + (sum[1] - sum[now]) - sum[now];
}
for(int i=0;i<ve[now].size();i++) {
int v = ve[now][i];
if(v == pre) continue;
DP(now, v);
}
}
int main() {
// freopen("1.in.txt", "r", stdin);
init();
dp[1] = dfs1(-1, 1, 0);//获得root的答案
dfs2(-1, 1);//预处理出所有子树的权值和
DP(-1, 1);//递归转移
ll Max = -1;
for(int i=1;i<=n;i++) Max = max(Max, dp[i]);
printf("%lld\n", Max);
return 0;
}