题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6662
题目大意:
一颗树的n个节点,A和B两个人每次选一个节点,在一个人选了第i个节点后,两个人分别获得贡献为 ai 和 bi。
每次选的节点必须与上一个人选的节点相连,且一个点只能被选一次,每个人的目的为使自己获得的总贡献减去对方的值最大。
保证每个人都选最优解,A先选,问A能获得的最大差值是多少
思路:
刚做过一道类似的题,CF731E,同样为两个人取值使差值最大,故用相同思路
即将dp数组设计为二维,一维表示位置,第二维0/1,分别表示该点由A选时A与B的最大差值 和 该点由B选时B与A的最大差值
由于选定一个点后,对方有可能向父节点方向选,也有可能向子节点方向
故用换根dp,第一次dfs求任意一个节点作为起点的答案,第二次dfs求出每个节点作为起点的答案。
转移思路为当A选了一个节点,那么下一个节点由B选时一定会使B-A的差值尽可能大。
因此转移时倒着考虑,可得每次由最小值转移来。
方程可得
dp[u][1] = min( a[u] - b[u] - dp[v][0] )
dp[u][0] = min( b[u] - a[u] - dp[v][1] )
在第二遍dfs时,对于每个节点可能从父节点转移,也可能从子节点转移。
而在由父节点转移时需要先将父节点由该节点转移来的结果去掉,防止结果出现先从子节点转移到父节点再转移回子节点。
故需要维护一个前缀最小值和一个后缀最小值,也可对每个点维护最小值与次小值来完成。
因为第二种方法代码量较大,此处便采取第一种。
(此处思路参考了其他博客QAQ)
代码见下
#include <bits/stdc++.h>
using namespace std;
typedef pair<long long,long long> P;
long long dp[100005][2],a[100005],b[100005];
vector<int> E[100005];
vector<P> pre[100005];
long long inf=0x3f3f3f3f3f3f3f3f;
long long res=-inf;
void dfs1(int x,int fa){
dp[x][0]=inf;
dp[x][1]=inf;
for(auto i:E[x]){
if(i==fa) continue;
dfs1(i,x);
dp[x][0]=min(dp[x][0],b[x]-a[x]-dp[i][1]);
dp[x][1]=min(dp[x][1],a[x]-b[x]-dp[i][0]);
}
if(dp[x][0]==inf)
dp[x][0]=b[x]-a[x],
dp[x][1]=a[x]-b[x];
}
void dfs2(int x,int fa){
dp[x][0]=inf;
dp[x][1]=inf;
for(auto i:E[x]){
dp[x][0]=min(dp[x][0],b[x]-a[x]-dp[i][1]);
dp[x][1]=min(dp[x][1],a[x]-b[x]-dp[i][0]);
pre[x].push_back(P(dp[x][0],dp[x][1]));
}
long long t0=inf,t1=inf;
for(int i=E[x].size()-1;i>=0;i--){
int v=E[x][i];
dp[x][0]=t0;
dp[x][1]=t1;
if(i>0){
dp[x][0]=min(dp[x][0],pre[x][i-1].first);
dp[x][1]=min(dp[x][1],pre[x][i-1].second);
}
if(dp[x][0]==inf)
dp[x][0]=b[x]-a[x],dp[x][1]=a[x]-b[x];
t0=min(t0,b[x]-a[x]-dp[v][1]);
t1=min(t1,a[x]-b[x]-dp[v][0]);
if(v!=fa)
dfs2(v,x);
}
//cout<<x<<" "<<dp[x][0]<<" "<<t0<<endl;
dp[x][0]=t0;
dp[x][1]=t1;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--){
int n;
cin>>n;
res=-inf;
for(int i=1;i<=n;i++) E[i].clear();
for(int i=1;i<=n;i++) pre[i].clear();
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
E[x].push_back(y);
E[y].push_back(x);
}
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++) res=max(res,dp[i][1]);
cout<<res<<endl;
}
}