H. Crystalfly
思路:
f
[
u
]
f[u]
f[u] 表示以
u
u
u 为根的子树所能获得的最大值
g
[
u
]
g[u]
g[u] 表示走到
u
u
u 然后立即返回能获得的值
假设
u
u
u 的子节点为 j
g
[
u
]
+
=
f
[
j
]
−
a
[
j
]
g[u] += f[j] - a[j]
g[u]+=f[j]−a[j] 拿不到
u
u
u 的所有直接子节点
j
j
j
f
[
u
]
f[u]
f[u] 的更新:
首先 如果
u
u
u 没有子节点则
f
[
u
]
=
g
[
u
]
f[u] = g[u]
f[u]=g[u], 如果叶子节点不是,则为
f
[
u
]
=
g
[
u
]
+
a
[
j
]
f[u] = g[u] + a[j]
f[u]=g[u]+a[j]
然后 如果
t
[
j
]
=
=
3
t[j] == 3
t[j]==3, 那么可以先去采一下
u
u
u 的其他直接子节点, 然后再回来拿采
j
j
j
假设这里去拿了点
z
z
z
则
z
z
z 对最后答案的贡献会变为为 g[z], 又因为 g[u] 中已经包含了一次
f
[
z
]
−
a
[
z
]
f[z] - a[z]
f[z]−a[z], 所以需要减掉重复部分
为了求对最终
f
[
u
]
f[u]
f[u] 的最大贡献,就需要求一下
g
[
z
]
−
(
f
[
z
]
−
a
[
z
]
)
g[z] - (f[z] - a[z])
g[z]−(f[z]−a[z]) 的最大值与次大值 用于更新最后的
f
[
u
]
f[u]
f[u]
代码:
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
int n;
const int N = 1e5 + 10, M = N * 2;
int e[M], ne[M], h[N], idx;
ll t[N], f[N], g[N], a[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int fa) {
g[u] = a[u];
ll maxn1 = 0, maxn2 = 0;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == fa) continue;
dfs(j, u);
g[u] += f[j] - a[j]; // 拿 u 但是不拿 u 的直接子节点
ll temp = g[j] - (f[j] - a[j]);
if(maxn1 < temp) {
maxn2 = maxn1;
maxn1 = temp;
} else if(maxn2 < temp) maxn2 = temp;
}
f[u] = g[u]; //删掉后叶子节点无法更新
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == fa) continue;
f[u] = max(f[u], g[u] + a[j]);
if(t[j] == 3) {
if(g[j] - f[j] + a[j] == maxn1) f[u] = max(f[u], g[u] + a[j] + maxn2);
else f[u] = max(f[u], g[u] + a[j] + maxn1);
}
}
}
void solve() {
cin >> n;
memset(h, -1, sizeof h);
idx = 0;
for(int i = 1; i <= n; i ++) cin >> a[i], f[i] = g[i] = 0;
for(int i = 1; i <= n; i ++) cin >> t[i];
for(int i = 1; i < n; i ++) {
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1, -1);
cout << f[1] << '\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) solve();
}