假如要求的这个点v是根节点,那么我们可以dp,一个值为1的节点,他的值等于他所有子树中,dp为为正数的和。也就是
d
p
[
u
]
=
∑
v
=
u
的
所
有
儿
子
且
d
p
[
v
]
为
正
数
d
p
[
v
]
+
(
a
[
u
]
=
=
1
)
dp[u]=\sum_{v=u的所有儿子且dp[v]为正数}dp[v]+(a[u]==1)
dp[u]=v=u的所有儿子且dp[v]为正数∑dp[v]+(a[u]==1)
所以f的递归式是这样的:
f
(
u
)
=
d
p
[
u
]
+
m
a
x
(
x
,
0
)
f(u)=dp[u]+max(x,0)
f(u)=dp[u]+max(x,0) 其中
x
=
f
(
f
a
[
u
]
)
−
m
a
x
(
d
p
[
5
]
,
0
)
x=f(fa[u])-max(dp[5],0)
x=f(fa[u])−max(dp[5],0)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<map>
#include<queue>
#include<cstdio>
#include<set>
#include<map>
#include<string>
using namespace std;
const int maxn = 2e5 + 10;
int n, a[maxn], dp[maxn];
vector<int> g[maxn];
int memo[maxn], fa[maxn];
int f(int u, int faa = 0)
{
if (memo[u] != -2)
return memo[u];
if (faa != 0) fa[u] = faa;
int sum = 0;
for (auto& v : g[u]) if (v != faa)
sum += max(f(v, u), 0);
return memo[u] = sum + (a[u] == 1 ? 1 : -1);
}
int memo2[maxn];
int h(int u)
{
if (u == 1) return f(1);
if (memo2[u] != -2)
return memo2[u];
int x = h(fa[u]) - max(f(u), 0);
return memo2[u] = f(u) + max(x, 0);
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i], memo[i] = memo2[i] = -2;
for (int i = 1; i <= n - 1; i++)
{
int u, v;
cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
for (int i = 1; i <= n; i++)
cout << h(i) << " ";
}
int main()
{
//freopen("Testin.txt", "r", stdin);
solve();
return 0;
}
F - Maximum White Subtree看我博客我有没看懂的地方,或者其他疑问,可以加我qq和我交流~我会及时解答qq:1244536605(加好友时备注一下 博客 哈)标签换根dp简明题意给定n个节点的树,每个节点的值为0或1.现在需要你对树的每个节点v求出:包含v的联通子图中,节点1的数量减去0的数量,最多是多少。思路假如要求的这个点v是根...