• [hdu-6662]Acesrc and Travel 树形DP 2019多校8


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6662

    题目大意:一棵树,点权是一个差值a-b,两个人(张和刘)在树上旅游,每个点只能走过一次,张想要走过的节点和最大,刘要走过的和最小,张先手然后两人交替选择下一个相邻的点走直到无路可走停止,两个人都会选择对自己的最优策略。求最大的和。

    ps:题目原意是张在每一个节点有一个满意度,刘有一个满意度,求满意度的差别最大。然后我理解成了两个人都想要差别的绝对值最大qwq,比赛时理解错题写错了

    题解:树形dp

    每段旅程的终点为叶子结点

    固定好树后,以每个节点为起点,有两种走法,向上和向下 我们要选择其中最优的

    1.  向下维护:一遍dfs

    maxx[v] : v点张选择往下走得最大值

    minn[v]  : v点刘选择往下走得最小值

    maxx[v]=  max( minn[ son ] ) +  v[i]    张会选择往后 刘做选择 得到的最大的

    minn[v]=   min( maxn[ son ] ) +  v[i]    刘会选择往后 张做选择 得到的最小的

    2.向上维护:要考虑当前点的后手(父亲)会做对他最优的选择

    当前点父亲  可以是沿着父亲一直往上走,或者向下走到兄弟的最优   

    如果当前点是父亲往下走最优时的那条路,就是往上走或者走父亲向下的 次优

    zhang[v] : v点张选择往上走得最大值

    liu[v]  : v点刘选择往上走得最小值

    zhang[v] = min( liu [ father ] , minn[ father ] )    当前张做选择往上走  父亲刘会选择  向上 或 向下(1中维护过) 中更小的一个走

    liu[v] = max( zhang [ father ], maxx[ father ] )    当前刘做选择往上走  父亲张会选择 向上 或 向下  中更大的一个走

    用每个点liu做选择的最优答案(说明这个起始点是张选的)更新答案

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int const maxn=1e5+100;
    int tot,n,head[maxn],fa[maxn];
    long long  ans,son[maxn],a[maxn],minn[maxn],maxx[maxn],fmi[maxn],fmaa[maxn],danma[maxn],danmi[maxn];
    ll zhang[maxn],liu[maxn];
    //max[x]当前x点往下走张做选择 min[x] 当前点x往下走刘做选择
    //zhang[x]当前点往上走张做选择 liu[x] 往上走刘做选择
    struct edge{
        ll to, nex;
    }e[maxn<<1];
    void builde(int x,int y){
        e[++tot].to=y,e[tot].nex=head[x];head[x]=tot;
    }
    inline int  get_num(){
        char ch;
        int num=0;
        ch=getchar();
        while(ch<'0'||ch>'9'){ch=getchar();}
        while(ch>='0'&&ch<='9'){num=(num<<3)+(num<<1)+ch-'0';ch=getchar();}
        return num;
    }
    void dfs(int x){
        ll nmin=2e18,nmax=-(2e18),nit=2e18,nat=-(2e18);//记录前两大和前两小
        int to;
        minn[x]=maxx[x]=danmi[x]=danma[x]=a[x];
        for(int i=head[x];i;i=e[i].nex){
            to=e[i].to;
            if(to==fa[x])continue;
            fa[to]=x;
            dfs(to);
            son[x]++;
            if(maxx[to]<nmin){ nit=nmin, nmin=maxx[to],fmi[x]=to;}
            else if(maxx[to]<nit)nit=maxx[to];//刘会选择后手张做选择中最小的
            if(minn[to]>nmax){ nat=nmax, nmax=minn[to],fmaa[x]=to;}
            else if(minn[to]>nat)nat=minn[to];//张会选择后手刘做选择中最大的
        }
        if(son[x]){
            maxx[x]+=nmax,minn[x]+=nmin;
        }
        if(son[x]>1){
            danmi[x]=nit+a[x];danma[x]=nat+a[x];
        }
    }
    void dfs2(int x){
        for(int i=head[x];i;i=e[i].nex){
            int to=e[i].to;
            if(to==fa[x])continue;
            if(son[x]==1){
                zhang[to]=liu[x]+a[to];//如果儿子只有一个,那这个儿子只能沿着父亲往上走
                liu[to]=zhang[x]+a[to];
            }
            else{//如果有多个儿子,它可以沿着父亲往上走,或者走他的兄弟中对他最优的,【注意如果是原先父亲结点的最优来源,那应该走次优的那条兄弟路线
                ll rr=(to==fmaa[x])?rr=danma[x]:maxx[x];
                ll lu=(to==fmi[x])?lu=danmi[x]:minn[x];
                if(x!=1)rr=max(zhang[x],rr),lu=min(liu[x],lu);//
                liu[to]=rr+a[to];
                zhang[to]=lu+a[to];
            }
            dfs2(to);
        }
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            memset(head,0,sizeof head);
            memset(son,0,sizeof(son));
            memset(fmi,0,sizeof fmi);
            memset(fmaa,0,sizeof fmaa);
            scanf("%d",&n);
            tot=0;
            for(int i=1;i<=n;i++)a[i]=get_num();
            for(int i=1;i<=n;i++)a[i]-=get_num();
            int p,q;
            for(int i=1;i<n;i++){
                p=get_num(),q=get_num();
                builde(p,q);builde(q,p);
            }
            
            dfs(1);
            zhang[1]=liu[1]=a[1];ans=minn[1];
            dfs2(1);
            //每个点只能用liu(起始点刘做选择说明起始点是张选的)更新一次答案,用上下走或向上走最优的那个
            for(int i=2;i<=n;i++){
                if(son[i])ans=max(ans,min(liu[i],minn[i]));//非儿子可以选择往上或往下走对自己最优的
                else ans=max(ans,liu[i]);//儿子做起点只能往上走
            }
            //for(int i=1;i<=n;i++)cout<<maxx[i]<<' '<<minn[i]<<endl;
            printf("%lld
    ",ans);
        }
        return 0;
    }

    标程:

     1 #include<bits/stdc++.h>
     2 #define maxn 202000
     3 #define x first
     4 #define y second
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 typedef pair<ll,ll> pi;
     9 const ll inf=1e16;
    10 ll a[maxn],n,k,query,ans,p[maxn],q[maxn],d[maxn];
    11 vector <int> h[maxn];
    12 pi f[maxn],g[maxn];
    13 
    14 void dfs(int fa,int u)
    15 {
    16     for (int i=0;i<h[u].size();i++)
    17     {
    18         int v=h[u][i];
    19         if (v==fa) continue;
    20         dfs(u,v),d[u]++;
    21         if (f[u].x<a[u]+g[v].x) f[u].y=f[u].x,f[u].x=a[u]+g[v].x;
    22         else if (f[u].y<a[u]+g[v].x) f[u].y=a[u]+g[v].x;
    23         if (g[u].x>a[u]+f[v].x) g[u].y=g[u].x,g[u].x=a[u]+f[v].x;//g先手
    24         else if (g[u].y>a[u]+f[v].x) g[u].y=a[u]+f[v].x;
    25     }
    26     if (!d[u]) f[u].x=f[u].y=g[u].x=g[u].y=a[u];
    27 }
    28 
    29 void dfs2(int fa,int u)
    30 {
    31     for (int i=0;i<h[u].size();i++)
    32     {
    33         int v=h[u][i]; ll r;
    34         if (v==fa) continue;
    35         if (d[u]==1) p[v]=q[u]+a[v],q[v]=p[u]+a[v];
    36         else {
    37             r=(f[u].x==g[v].x+a[u])?f[u].y:f[u].x;
    38             if (u!=1) r=max(r,q[u]); p[v]=r+a[v];
    39             r=(g[u].x==f[v].x+a[u])?g[u].y:g[u].x;
    40             if (u!=1) r=min(r,p[u]); q[v]=r+a[v];
    41         }
    42         dfs2(u,v);
    43     }
    44 }
    45 int main()
    46 {
    47     //freopen("test1.in","r",stdin);
    48     //freopen("test2.out","w",stdout);
    49     scanf("%lld",&query);
    50     while (query--){
    51         scanf("%lld",&n);
    52         //printf("%d
    ", n);
    53         for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    54         for (int i=1;i<=n;i++) {scanf("%lld",&k); a[i]-=k;}
    55         for (int i=1;i<=n;i++) h[i].clear(),d[i]=0,f[i].x=f[i].y=-inf,g[i].x=g[i].y=inf;
    56         for (int i=1;i<n;i++)
    57         {
    58             int u,v; scanf("%d%d",&u,&v);
    59             h[u].push_back(v);
    60             h[v].push_back(u);
    61         }
    62         dfs(0,1); p[1]=q[1]=a[1]; dfs2(0,1); ans=g[1].x;
    63         //for (int i=1;i<=n;i++) cout << p[i] << ' ' << q[i] << endl;
    64         //for (int i=1;i<=n;i++) cout << f[i].x << ' ' << f[i].y << ' ' << g[i].x << ' ' << g[i].y << endl;
    65         for (int i=2;i<=n;i++) if (d[i]) ans=max(ans,min(g[i].x,p[i])); else ans=max(ans,p[i]);
    66         cout << ans << endl;
    67     }
    68     return 0;
    69 }
  • 相关阅读:
    Java-- 异常之使用finally进行清理
    请几天假
    Java-- 重新抛出异常
    Java-- 异常与记录日志
    Java-- 异常(2)
    Java基础——多线程(4)
    Java基础——多线程(3)
    Java基础——面向对象练习题
    Java基础——多线程(2)
    Java基础——多线程(1)
  • 原文地址:https://www.cnblogs.com/conver/p/11357531.html
Copyright © 2020-2023  润新知