http://acm.hdu.edu.cn/showproblem.php?pid=6662
题意:有两个人在树上博弈,每个点节点有两个分数a[i]和b[i],先手先选择一个点,后手在先手选的点的相邻点中选择一个点,然后先手在后手选的点的相邻点中选择一个两个人都没有走过的点,直到不能走,游戏就结束。一个人走到节点x,那么先手会获得分数a[x],后手就会会获得分数b[x]。最后询问先手能获得与后手的差值最大值。
思路:先手固定好位置后,后手走。有两种走法,向下和向上。
向下好办,用down[i][0]表示我从i走到i的儿子后所能得到的最大值,down[i][1]为对手走的最小值,那么down[i][0] = v[i]+max(down[son][1]), down[i][1]=v[i]+min(down[son][0])
向上的话,走完后对面也分为向上或向下。
向下走时,不能走当前上去的路,所以存每个点向下走的最值和次值,当最值和上去那条路得出的值相同,就换成次值。
向上走时,从上到下一路维护即可。

1 #include<bits/stdc++.h>
2 #define ll long long
3 #define rep(i,a,b) for(int i=a;i<=b;i++)
4 using namespace std;
5 const int maxn = 1e5+5;
6 const ll inf = 0x3f3f3f3f3f3f3f3f;
7 ll a[maxn],b[maxn];
8 int head[maxn],fa[maxn],to[maxn<<2],nex[maxn<<2],now;
9
10 void add(int a,int b){
11 nex[++now] = head[a];
12 head[a] = now;
13 to[now] = b;
14 }
15
16 ll down[maxn][2][2],up[maxn][2];
17 bool lef[maxn];
18
19 void dfs(int p){
20 down[p][0][0] = down[p][0][1] = -inf;
21 down[p][1][0] = down[p][1][1] = inf;
22 lef[p] = 1;
23 for(int i=head[p];i;i=nex[i]){
24 if(to[i]==fa[p]) continue;
25 lef[p] = 0;
26 fa[to[i]] = p;
27 dfs(to[i]);
28 if(down[to[i]][1][0]+a[p]>=down[p][0][0]){
29 down[p][0][1] = down[p][0][0];
30 down[p][0][0] = down[to[i]][1][0]+a[p];
31 }
32 else if(down[to[i]][1][0]+a[p]>=down[p][0][1]){
33 down[p][0][1] = down[to[i]][1][0]+a[p];
34 }
35 if(down[to[i]][0][0]+a[p]<=down[p][1][0]){
36 down[p][1][1] = down[p][1][0];
37 down[p][1][0] = down[to[i]][0][0]+a[p];
38 }
39 else if(down[to[i]][0][0]+a[p]<=down[p][1][1]){
40 down[p][1][1] = down[to[i]][0][0]+a[p];
41 }
42 }
43 if(lef[p]) down[p][0][0] = down[p][1][0] = a[p];
44 }
45
46 ll Abs(ll a){
47 return a>0?a:-a;
48 }
49
50 void Dfs(int p){
51 if(fa[p]==-1) up[p][0] = up[p][1] = inf;
52 else {
53 up[p][0] = inf;
54 ll _down = down[fa[p]][1][0];
55 if(_down==a[fa[p]]+down[p][0][0])
56 _down = down[fa[p]][1][1];
57 if(Abs(_down)!=inf)
58 up[p][0] = min(up[p][0],a[p]+_down);
59 if(fa[p]!=1)
60 up[p][0] = min(up[p][0],a[p]+up[fa[p]][1]);
61 if(up[p][0]==inf)
62 up[p][0] = a[p]+a[fa[p]];
63
64 up[p][1] = -inf;
65 _down = down[fa[p]][0][0];
66 if(_down==a[fa[p]]+down[p][1][0])
67 _down=down[fa[p]][0][1];
68 if(Abs(_down)!=inf)
69 up[p][1]=max(up[p][1],a[p]+_down);
70
71 if(fa[p]!=1)
72 up[p][1]=max(up[p][1],a[p]+up[fa[p]][0]);
73
74 if(up[p][1]==-inf)
75 up[p][1]=a[p]+a[fa[p]];
76 }
77 for(int i=head[p];i;i=nex[i]){
78 if(to[i]==fa[p])continue;
79 Dfs(to[i]);
80 }
81 }
82
83
84
85 int main(){
86 ios::sync_with_stdio(0);
87 cin.tie(0);
88 cout.tie(0);
89 int t;
90 cin>>t;
91 while(t--){
92 memset(head,0,sizeof head);
93 now = 0;
94 int n;
95 cin>>n;
96 rep(i,1,n) cin>>a[i];
97 rep(i,1,n) cin>>b[i], a[i]-=b[i];
98 rep(i,1,n-1){
99 int u,v;
100 cin>>u>>v;
101 add(u,v);
102 add(v,u);
103 }
104 if(n==1){
105 cout<<a[1]<<endl;
106 continue;
107 }
108 fa[1] = -1;
109 dfs(1);
110 Dfs(1);
111 ll ans = -inf;
112 for(int i=1;i<=n;i++){
113 ll res = inf;
114 if(!lef[i]) res = min(res,down[i][1][0]);
115 if(i!=1) res = min(res,up[i][1]);
116 ans = max(ans,res);
117 }
118 cout<<ans<<endl;
119 }
120 return 0;
121 }
