题意就是给一个无根树,然后每次从一个点出发,两个人轮流决定下一点;对于一个点,Zhang获得a[i],Liu获得b[i]。每个人都想自己获得的与另一个人的差最大,求Zhang先手的最大差值。
Source:2019 Multi-University Training Contest 8
一个最大差值,一定是当前的点减去之前的最小值得到的,有状态转移:f(u,v,0)=min{f(p,u,1)}f(u,v,1)=min{f(p,u,0)}f(u,v,0)=\min\{f(p,u,1)\} \\f(u,v,1)=\min\{f(p,u,0)\} f(u,v,0)=min{f(p,u,1)}f(u,v,1)=min{f(p,u,0)}
因为起点是不确定的,考虑换根。再做一个dfs,向下扩展时,为了防止扩展到已扩展的节点,每次对于当前扩展的节点,记录一个前缀最小值。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#define inf 0x7fffffffffffffff
#define ll long long
#define mem(a, x) memset(a,x,sizeof(a))
#define iosup ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef pair<ll, ll> Pll;
const int N = 1e5 + 10;
ll dp[N][2], a[N], b[N];
vector<int> G[N];
vector<Pll> pre[N];
int n;
void dfs1(int u, int fa) {
dp[u][0] = inf;
dp[u][1] = inf;
for (auto i:G[u])
if (i != fa) {
dfs1(i, u);
dp[u][0] = min(dp[u][0], b[u] - a[u] - dp[i][1]);
dp[u][1] = min(dp[u][1], a[u] - b[u] - dp[i][0]);
}
if (dp[u][0] == inf)
dp[u][0] = b[u] - a[u], dp[u][1] = a[u] - b[u];
}
void dfs2(int u, int fa) {
dp[u][0] = inf;
dp[u][1] = inf;
for (auto i:G[u]) {
dp[u][0] = min(dp[u][0], b[u] - a[u] - dp[i][1]);
dp[u][1] = min(dp[u][1], a[u] - b[u] - dp[i][0]);
pre[u].push_back(Pll(dp[u][0], dp[u][1]));
}
ll t0 = inf, t1 = inf;
for (int i = G[u].size() - 1; i >= 0; i--) {
int v = G[u][i];
dp[u][0] = t0;
dp[u][1] = t1;
if (i) {
dp[u][0] = min(dp[u][0], pre[u][i - 1].first);
dp[u][1] = min(dp[u][1], pre[u][i - 1].second);
}
if (dp[u][0] == inf)
dp[u][0] = b[u] - a[u], dp[u][1] = a[u] - b[u];
t0 = min(t0, b[u] - a[u] - dp[v][1]);
t1 = min(t1, a[u] - b[u] - dp[v][0]);
if (v != fa)
dfs2(v, u);
}
dp[u][0] = t0;
dp[u][1] = t1;
}
inline void init() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) G[i].clear();
for (int i = 1; i <= n; i++) pre[i].clear();
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++)
scanf("%lld", &b[i]);
int u, v;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T;
cin >> T;
while (T--) {
init();
dfs1(1, 1);
dfs2(1, 1);
ll ans = -inf;
for (int i = 1; i <= n; i++)
ans = max(ans, dp[i][1]);
printf("%lld\n", ans);
}
return 0;
}