HDU6662 Acesrc and Travel
题意
给一棵树,每个点有权值a和b,两人博弈,先手选一个点开始走,两人轮流走相邻且没走过的点直至无法再走。每到一个点,先手得a分,后手得b分。求两人都使用最优策略的情况下,两人分数差。
题目链接
思路
树形dp,求出每个点先手选择它,走到它子树的叶子节点的最大次大值,用f[x][0]表示,以及每个点后手选择它,走到它子树的叶子节点的最小次小值,用f[x][1]表示。再dfs一遍,过程中维护向它父亲走,它的父亲是先后手的值。特殊考虑的情况是如果是叶子节点只能向父亲走,根节点是叶子节点额外维护。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 1e16;
const int maxn = 100000+10;
int n;
int a[maxn],b[maxn],c[maxn];
int pre[2*maxn],other[2*maxn],last[maxn],du[maxn];
LL f1[maxn][2],f2[maxn][2];
int tot;
LL ans;
bool jud;
void add(int x,int y)
{
tot++;
pre[tot]=last[x];
last[x]=tot;
other[tot]=y;
du[y]++;
}
void dfs1(int x,int fa)
{
LL mn1=INF,mx1=-INF;
LL mn2=INF,mx2=-INF;
int num=0;
for (int p=last[x];p;p=pre[p])
{
int q=other[p];
if (q==fa) continue;
num++;
dfs1(q,x);
if (f1[q][1]<=mn1)
{
mn2=mn1;
mn1=f1[q][1];
} else
if (f1[q][1]<mn2)
{
mn2=f1[q][1];
}
if (f1[q][0]>=mx1)
{
mx2=mx1;
mx1=f1[q][0];
} else
if (f1[q][0]>mx2)
{
mx2=f1[q][0];
}
}
if (num==0) mn1=mx1=0;
f1[x][0]=c[x]+mn1;
f2[x][0]=c[x]+mn2;
f1[x][1]=c[x]+mx1;
f2[x][1]=c[x]+mx2;
if (x==1&&num==1) jud=1;
}
void dfs2(int x,int fa,LL pre0,LL pre1)
{
if (x==1) ans=max(ans,f1[x][0]); else
if (du[x]==1) ans=max(ans,pre1+c[x]); else ans=max(ans,min(f1[x][0],pre1+c[x]));
for (int p=last[x];p;p=pre[p])
{
int q=other[p];
if (q==fa) continue;
LL p0,p1;
if (x==1)
{
if (jud)
{
p0=p1=c[x];
} else
{
if (f1[x][0]==f1[q][1]+c[x]) p0=f2[x][0]; else p0=f1[x][0];
if (f1[x][1]==f1[q][0]+c[x]) p1=f2[x][1]; else p1=f1[x][1];
}
} else
{
if (f1[x][0]==f1[q][1]+c[x]) p0=min(f2[x][0],pre1+c[x]); else p0=min(f1[x][0],pre1+c[x]);
if (f1[x][1]==f1[q][0]+c[x]) p1=max(f2[x][1],pre0+c[x]); else p1=max(f1[x][1],pre0+c[x]);
}
dfs2(q,x,p0,p1);
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
tot=0;
for (int i=1;i<=n;i++) last[i]=0,du[i]=0;
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
for (int i=1;i<=n;i++) c[i]=a[i]-b[i];
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
jud=0;
dfs1(1,0);
ans=-INF;
dfs2(1,0,0,0);
printf("%lld\n",ans);
}
return 0;
}