zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    mybatis中大于等于小于等于的写法
    RandomAccess接口
    ArrayList源码解析
    使用Docker搭建MySQL主从复制(一主一从)
    狂神Docker视频学习笔记(基础篇)
    【JQ】jQuery实现将div中滚动条滚动到指定位置的方法
    JAVA线程池的基本使用
    史上最全的Java技术体系思维导图,没有之一!
    springboot整合kafka
    spring cloud alibaba 分布式事务解决方案之seata-1.3.0
  • 原文地址:https://www.cnblogs.com/zhanggengchen/p/11425381.html
Copyright © 2011-2022 走看看