传送门
题意: 一棵树,每个点分为黑色或白色,问包含每个点的
c
n
t
白
点
−
c
n
t
黑
点
cnt_{白点}-cnt_{黑点}
cnt白点−cnt黑点 最大的子树
看了题解,挺妙的,先求出对于一个随意的根的答案(递归),然后换根
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N];
vector<int> g[N];
int ans[N], dp[N];
inline void dfs(int x, int p) {
dp[x] = a[x];
int siz = g[x].size();
for(int i = 0; i < siz; ++ i) {
int to = g[x][i];
if(to == p) continue;
dfs(to, x);
dp[x] += max(0, dp[to]);
}
}
inline void dfs2(int x, int p) {
int siz = g[x].size();
ans[x] = dp[x];
for(int i = 0; i < siz; ++ i) {
int to = g[x][i];
if(to == p) continue;
dp[x] -= max(0, dp[to]);
dp[to] += max(0, dp[x]);
dfs2(to, x);
dp[to] -= max(0, dp[x]);
dp[x] += max(0, dp[to]);
}
}
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n;
cin >> n;
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
if(a[i] == 0) a[i] = -1;
}
for(int i = 1, x, y; i < n; ++ i) {
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1, -1);
dfs2(1, -1);
for(int i = 1; i <= n; ++ i) {
cout << ans[i] << " ";
}
return 0;
}