• 【三中校内训练】旅行


     

     【题解】

    显然的这是一道树形DP的题目

    这里令f[i][0]为从i出发向以它为根的子树里走直到不能走的最大、最小价值

    (不能走是什么自己阅读题目)

    令s为x的儿子,w[i][j]为i和j之间的边的长度,则

    f[x][0]=max(f[s][1]+w[s][i])

    f[x][1]=min(f[s][0]+w[s][i])

    显然的通过这种方法,我们可以得到60分

    可是,如何优化到线性呢

    我们考虑一个节点x,x向某条边走的情况出现了很多次,浪费了很多时间

    我们定义h[x][0/1]为从x出发,经过x的父亲fa走到不能走为止的最大、最小价值

    显然的h[x][0]会被x的兄弟节点y的f[y][1]和h[fa][1]影响,

    h[x][1]会被x的兄弟节点y的f[y][0]和x父亲fa的h[fa][0]影响,

    我们要从中选取一个最大的或者最小的计入答案

    但是为了防止被自己这颗子树更新,我们需要求一个次小和次大

    以x为根的树的答案可以顺便处理,具体看代码

    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #define mod 1000000007
    #define il inline
    using namespace std;
    const int N=1000001;
    typedef long long ll;
    struct edge{int next,to,val;} e[N];
    int n,M,g[N];
    ll f[N][2],p[N][2],ans[N];
    il void addedge(int x,int y,int z){
        e[++M]=(edge){g[x],y,z};g[x]=M;
    }
    il void dfs1(int h,int fa){
        f[h][1]=(1ll<<50);f[h][0]=0;
        for(int i=g[h];i;i=e[i].next){
            if(e[i].to==fa) continue;
            dfs1(e[i].to,h);
            f[h][0]=max(f[h][0],f[e[i].to][1]+e[i].val);
            f[h][1]=min(f[h][1],f[e[i].to][0]+e[i].val);
        }
        if(f[h][1]==(1ll<<50)) f[h][1]=0;
    }
    il void dfs2(int h,int fa){
        ll s1=(1ll<<50),s2=(1ll<<50),l1=0,l2=0,x,y;
        for(int i=g[h];i;i=e[i].next){
            if(e[i].to==fa) continue;
            x=f[e[i].to][1]+e[i].val;
            y=f[e[i].to][0]+e[i].val;
            if(x>l1){l2=l1;l1=x;}
            else if(x>l2) l2=x;
            if(y<s1){s2=s1;s1=y;}
            else if(y<s2) s2=y;
        }
        if(h>1){
            if(p[h][0]>l1){l2=l1;l1=p[h][0];}
            else if(p[h][0]>l2) l2=p[h][0];
            if(p[h][1]<s1){s2=s1;s1=p[h][1];}
            else if(p[h][1]<s2) s2=p[h][1];
        }
        for(int i=g[h];i;i=e[i].next){
            if(e[i].to==fa) continue;
            x=f[e[i].to][1]+e[i].val;
            y=f[e[i].to][0]+e[i].val;
            if(x==l1) p[e[i].to][1]=l2+e[i].val;
            else p[e[i].to][1]=l1+e[i].val;
            if(y==s1) p[e[i].to][0]=s2+e[i].val;
            else p[e[i].to][0]=s1+e[i].val;
            dfs2(e[i].to,h);
        }
        ans[h]=l1;
    }
    int main(){
        freopen("travel.in","r",stdin);
        freopen("travel.out","w",stdout);
        scanf("%d",&n);
        for(int i=1,x,y,z;i<n;i++){
            scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
            addedge(y,x,z);
        }
        dfs1(1,0);dfs2(1,0);
        for(int i=1;i<=n;i++) printf("%lld
    ",ans[i]);
        return 0;
    }

     

  • 相关阅读:
    linux下自动同步internet时间
    String,StringBuffer与StringBuilder的区别
    Spring Boot CLI安装
    java中Date与String的相互转化
    MyBatis Sql语句中的转义字符
    MyBatis详解 与配置MyBatis+Spring+MySql
    MyBatis的foreach语句详解
    不可变集合 Immutable Collections
    Java日期时间使用总结
    Java将一段逗号分割的字符串转换成一个数组
  • 原文地址:https://www.cnblogs.com/ExiledPoet/p/6067392.html
Copyright © 2020-2023  润新知