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;
}
posted @ 2019-08-28 17:34  zhanggengchen  阅读(171)  评论(0编辑  收藏  举报