zoukankan      html  css  js  c++  java
  • [BZOJ4446][SCOI2015]小凸玩密室(树形DP)

    密室玩小凸。

    完全二叉树关于复杂度的两个性质:

    1.所有点的深度和为$O(nlog n)$

    2.所有点的子树内的叶子个数和为$O(nlog n)$

    根据这两个性质可以分别解决此题。

    下面使用第二个性质,参考:https://www.cnblogs.com/Gloid/p/9874570.html

    f[i][j]表示从i点开始,遍历i的子树,最后在j停止的最优解(其中j为i的子树中的某个叶子)。

    g[i][j]表示从i的子树中某个点开始,遍历i的子树,最后在j停止的最优解。

    f转移考虑四种情况:

      点亮左子树,点亮i,点亮右子树,或反之。

      点亮i,点亮左子树,点亮右子树,或反之。

    g转移考虑同样的四种情况,再与f取min。

    注意当i为叶子或只有一个儿子时特殊处理。

    细节要考虑清楚,为了保证空间使用vector记录子树内的叶子。

    小凸玩我。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=200010;
     9 const ll inf=1e16;
    10 int n,x;
    11 ll ans,v[N],rlen[N],llen[N],d[N];
    12 vector<int>son[N];
    13 vector<ll>f[N],g[N];
    14 
    15 void dfs(int x){
    16     int ls=x<<1,rs=ls|1;
    17     if (ls>n){ son[x].push_back(x); f[x].push_back(0); g[x].push_back(0); return; }
    18     d[ls]=d[x]+llen[x]; dfs(ls);
    19     if (rs>n){
    20         int lm=(int)son[ls].size()-1; ll mn=inf;
    21         rep(i,0,lm) son[x].push_back(son[ls][i]),mn=min(mn,f[ls][i]+(d[son[ls][i]]-d[x])*v[x]);
    22         rep(i,0,lm) f[x].push_back(f[ls][i]+llen[x]*v[ls]),g[x].push_back(f[x][i]);
    23         son[x].push_back(x); f[x].push_back(inf); g[x].push_back(mn);
    24         return;
    25     }
    26     d[rs]=d[x]+rlen[x]; dfs(rs);
    27     int lm=son[ls].size()-1,rm=son[rs].size()-1;
    28     ll mn1=inf,mn2=inf,mn3=inf,mn4=inf;
    29     rep(i,0,lm) son[x].push_back(son[ls][i]),mn1=min(mn1,f[ls][i]+(d[son[ls][i]]+d[rs]-2*d[x])*v[rs]);
    30     rep(i,0,rm) son[x].push_back(son[rs][i]),mn2=min(mn2,f[rs][i]+(d[son[rs][i]]+d[ls]-2*d[x])*v[ls]);
    31     rep(i,0,lm) f[x].push_back(rlen[x]*v[rs]+mn2+f[ls][i]),mn3=min(mn3,g[ls][i]+(d[son[ls][i]]-d[x])*v[x]);
    32     rep(i,0,rm) f[x].push_back(llen[x]*v[ls]+mn1+f[rs][i]),mn4=min(mn4,g[rs][i]+(d[son[rs][i]]-d[x])*v[x]);
    33     rep(i,0,lm) g[x].push_back(min(mn4+llen[x]*v[ls]+f[ls][i],f[x][i]));
    34     rep(i,0,rm) g[x].push_back(min(mn3+rlen[x]*v[rs]+f[rs][i],f[x][lm+i+1]));
    35 }
    36 
    37 int main(){
    38     freopen("bzoj4446.in","r",stdin);
    39     freopen("bzoj4446.out","w",stdout);
    40     scanf("%d",&n);
    41     rep(i,1,n) scanf("%lld",&v[i]);
    42     rep(i,2,n){
    43         scanf("%d",&x);
    44         if (i&1) rlen[i/2]=x; else llen[i/2]=x;
    45     }
    46     dfs(1); ans=inf; int tmp=(int)g[1].size()-1;
    47     rep(i,0,tmp) ans=min(ans,g[1][i]);
    48     printf("%lld
    ",ans);
    49     return 0;
    50 }
  • 相关阅读:
    list(range(10))解释
    numpy.random.normal函数
    适用于Python扩展程序包的非官方Windows二进制文件
    Linux--vi/vim编辑器常用命令
    Centos Mirrors List (centos7)
    windows--redis安装
    Celery 3.x 升级至 celery 4.x(转)
    windows/linux(centos7)安装SVN
    远程获取--snmp模块(python)/snmp-cmds,easysnmp
    FileZilla客户端(OS)连接Linux
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9878608.html
Copyright © 2011-2022 走看看