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 }