• bzoj4446 [Scoi2015]小凸玩密室


    Description

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

    Input

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

    Output

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

    Sample Input

    3
    5 1 2
    2 1

    Sample Output

    5

    HINT 

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

    正解:树形$dp$。

    一道超级神题。。

    首先看看题目告诉了我们什么信息吧:

    $1.$完全二叉树,所以树高是$logn$的。

    $2.$走过的点是一个连通块。

    $3.$走了一个点就必须把它的子树先走完。

    $4.$走到当前点的代价只和上一个点有关。

    那么我们考虑一下一条合法的行走路径,必定是先到一个点,然后把它的子树走完,然后走它的父亲,然后再走它的兄弟以及子树。

    那么我们就可以根据这个统计答案了,设$g[x][i]$表示$x$遍历子树以后再到$x$深度为$i$的祖先的最小值,因为树高是$logn$的,所以这个状态是显然可以设出来的。

    有了这个状态以后,我们就能模拟计算答案的过程了,我们只要枚举每一个点为起点然后走一下路径即可。

    现在的问题是$g[x][i]$该怎么求,首先如果$x$是叶子结点的话就很简单,就是$x$到深度为$i$的祖先的路径贡献。

    如果不是叶子结点且只有一个儿子,那么就是$x$到它儿子的路径贡献,再加上儿子遍历子树到深度为$i$的祖先的贡献。

    如果有两个儿子,就分类讨论一下先走左儿子还是右儿子,假设先走左儿子,那么就是$x$到左儿子的路径贡献,左儿子再遍历子树跳到右儿子的贡献,加上右儿子遍历子树到深度为$i$的祖先的贡献。

    这时,我们发现左儿子遍历子树再跳到右儿子这个贡献很不好算,那么我们再设一个状态,设$f[x][i]$表示$x$遍历子树以后再到深度为$i$的祖先的兄弟的最小值,这样就能实现$g$的转移了。

    于是我们的问题就变成了求$f[x][i]$,这个与$g[x][i]$求法类似,不再赘述。

    于是我们就成功地解决了这道题。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define N (200010)
     6 #define ls (x<<1)
     7 #define rs (x<<1|1)
     8 
     9 using namespace std;
    10 
    11 ll g[N][20],f[N][20],a[N],b[N],dis[N],ans;
    12 int dep[N],n;
    13 
    14 il int gi(){
    15   RG int x=0,q=1; RG char ch=getchar();
    16   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    17   if (ch=='-') q=-1,ch=getchar();
    18   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    19   return q*x;
    20 }
    21 
    22 int main(){
    23 #ifndef ONLINE_JUDGE
    24   freopen("light.in","r",stdin);
    25   freopen("light.out","w",stdout);
    26 #endif
    27   n=gi(),dep[1]=1; for (RG int i=1;i<=n;++i) a[i]=gi();
    28   for (RG int i=2;i<=n;++i) b[i]=gi(),dep[i]=dep[i>>1]+1,dis[i]=dis[i>>1]+b[i];
    29   for (RG int x=n,y,o;x>1;--x)
    30     for (RG int i=2;i<=dep[x];++i)
    31       if (ls>n) o=x>>(dep[x]-i+1),y=(x>>(dep[x]-i))^1,f[x][i]=(dis[x]+dis[y]-2*dis[o])*a[y];
    32       else if (ls==n) f[x][i]=a[n]*b[n]+f[n][i];
    33       else f[x][i]=min(a[ls]*b[ls]+f[ls][dep[x]+1]+f[rs][i],a[rs]*b[rs]+f[rs][dep[x]+1]+f[ls][i]);
    34   for (RG int x=n,y;x;--x)
    35     for (RG int i=0;i<=dep[x];++i)
    36       if (ls>n) y=x>>(dep[x]-i),g[x][i]=i?(dis[x]-dis[y])*a[y]:0;
    37       else if (ls==n) g[x][i]=a[n]*b[n]+g[n][i];
    38       else g[x][i]=min(a[ls]*b[ls]+f[ls][dep[x]+1]+g[rs][i],a[rs]*b[rs]+f[rs][dep[x]+1]+g[ls][i]);
    39   ans=g[1][0];
    40   for (RG int i=2;i<=n;++i){
    41     RG ll res=g[i][dep[i]-1];
    42     for (RG int x=i,y,o;x>1;x>>=1)
    43       y=x^1,o=x>>1,res+=y>n?(a[o>>1]*b[o]):(a[y]*b[y]+g[y][dep[o]-1]);
    44     ans=min(ans,res);
    45   }
    46   cout<<ans; return 0;
    47 }
  • 相关阅读:
    Wazuh配置电子邮件警报(SMTP)
    kafka 分区重新分配脚本
    shell并发及控制并发数
    python2和python3使用pyhive
    k8s1.17安装gitlab
    nginx ssl证书 BEGIN PRIVATE KEY 转换为BEGIN RSA PRIVATE KEY
    Datax:阿里云hbase数据导入到自建hbase集群
    python3连接impala(centos7)
    Effective Java2读书笔记-类和接口(五)
    Effective Java2读书笔记-类和接口(四)
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7695711.html
Copyright © 2020-2023  润新知