• BZOJ4446:[SCOI2015]小凸玩密室(树形DP)


    Description

    小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡。点亮所有灯泡即可逃出密室。
    每个灯泡有个权值Ai,每条边也有个权值bi。点亮第1个灯泡不需要花费,之后每点亮1个新的灯泡V的花费,等于上一个被点亮的灯泡U到这个点V的距离Du,v,乘以这个点的权值Av。
    在点灯的过程中,要保证任意时刻所有被点亮的灯泡必须连通,在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡。
    请告诉他们,逃出密室的最少花费是多少。

    Input

    第1行包含1个数n,代表节点的个数
    第2行包含n个数,代表每个节点的权值ai。(i=1,2,…,n)
    第3行包含n-l个数,代表每条边的权值bi,第i号边是由第(i+1)/2号点连向第i+l号点的边。(i=1,2...N-1)

    Output

    输出包含1个数,代表最少的花费。

    Sample Input

    3
    5 1 2
    2 1

    Sample Output

    5

    HINT

    对于100%的数据,1≤N≤2×10^5,1<Ai,Bi≤10^5

    Solution

    神仙树形DP

    一条合法的行走路径,一定是先走完一个点的子树,再访问它的兄弟的子树,访问完了就回到父节点。以此类推。

    也就是说要求从某个点出发,访问完其子树后回到某个祖先的最小代价。

    设$f[x][i]$表示从$x$开始访问完$x$的子树后再走到深度为$i$的祖先(设为$kfa$)的最小代价。

    设$g[x][i]$表示从$x$开始访问完$x$的子树后再走到深度为$i$的祖先的另外一个儿子的最小代价。

    $DP$完了之后枚举最开始先点亮哪个灯然后统计答案。因为是完全二叉树所以时空都是$nlogn$

    转移见代码,手画个图对比着理解效果应该会好一点……

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #define N (200009)
     4 #define LL long long
     5 #define ls (i<<1)
     6 #define rs (i<<1|1)
     7 #define kfa (i>>Depth[i]-j)
     8 using namespace std;
     9 
    10 LL n,Depth[N],Dist[N],a[N],b[N],g[N][21],f[N][21],ans=1e18;
    11 
    12 void DP()
    13 {
    14     for (int i=n; i>=1; --i)
    15         for (int j=0; j<=Depth[i]; ++j)
    16             if (ls>n)//当前是叶子 
    17             {
    18                 f[i][j]=(Dist[i]-Dist[kfa])*a[kfa];
    19                 g[i][j]=(Dist[i]-Dist[kfa]+b[kfa]+b[kfa^1])*a[kfa^1];
    20             }
    21             else if (ls==n)//只有左儿子
    22             {
    23                 f[i][j]=b[ls]*a[ls]+f[ls][j];
    24                 g[i][j]=b[ls]*a[ls]+g[ls][j];
    25             }
    26             else//左右儿子都有 
    27             {
    28                 f[i][j]=min(
    29                 b[ls]*a[ls]+g[ls][Depth[ls]]+f[rs][j],
    30                 b[rs]*a[rs]+g[rs][Depth[rs]]+f[ls][j]);
    31                 g[i][j]=min(
    32                 b[ls]*a[ls]+g[ls][Depth[ls]]+g[rs][j],
    33                 b[rs]*a[rs]+g[rs][Depth[rs]]+g[ls][j]);
    34             }
    35 }
    36 
    37 int main()
    38 {
    39     scanf("%lld",&n);
    40     for (int i=1; i<=n; ++i)
    41         scanf("%lld",&a[i]);
    42     for (int i=2; i<=n; ++i)
    43         scanf("%lld",&b[i]);
    44     for (int i=1; i<=n; ++i)
    45     {
    46         Depth[i]=Depth[i>>1]+1;
    47         Dist[i]=Dist[i>>1]+b[i];
    48     }
    49     DP(); 
    50     for (int i=1; i<=n; ++i)//枚举最先点哪个灯统计答案 
    51     {
    52         LL now=f[i][Depth[i]-1];
    53         for (int j=i; j!=1; j>>=1)
    54             if ((j^1)>n) now+=b[j>>1]*a[j>>2];
    55             else now+=b[j^1]*a[j^1]+f[j^1][Depth[j]-2];
    56         ans=min(ans,now);
    57     }
    58     printf("%lld
    ",ans);
    59 }
  • 相关阅读:
    IP,子网,子网掩码,网关,DNS到底都是啥(二)
    (能被11整除的数的特征)The shortest problem --hdu
    (匹配 匈牙利)棋盘游戏 -- Hdu --1281
    (匹配)Courses -- hdu --1083
    (匹配 最小路径覆盖)Air Raid --hdu --1151
    (匹配)The Accomodation of Students --HDU --2444
    (匹配)Fire Net --hdu --1045
    (二分匹配 模板)过山车 -- hdu --2063
    (连通图 ) Redundant Paths --POJ --3177
    (二分匹配 模板 KM)奔小康赚大钱--hdu--2255
  • 原文地址:https://www.cnblogs.com/refun/p/9890084.html
Copyright © 2020-2023  润新知