zoukankan      html  css  js  c++  java
  • loj #2009. 「SCOI2015」小凸玩密室

    #2009. 「SCOI2015」小凸玩密室

     

    题目描述

    小凸和小方相约玩密室逃脱,这个密室是一棵有 n nn 个节点的完全二叉树,每个节点有一个灯泡。点亮所有灯泡即可逃出密室。每个灯泡有个权值 Ai A_iAi​​,每条边也有个权值 bi b_ibi​​。

    点亮第 1 11 个灯泡不需要花费,之后每点亮一个新的灯泡 V VV 的花费,等于上一个被点亮的灯泡 U UU 到这个点 V VV 的距离 D(u,v) D(u, v)D(u,v),乘以这个点的权值 Av A_vAv​​。

    在点灯的过程中,要保证任意时刻所有被点亮的灯泡必须连通,在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡。请告诉他们,逃出密室的最少花费是多少。

    输入格式

    第一行包含一个数 n nn,代表节点的个数。
    第二行包含 n nn 个数,代表每个节点的权值 ai a_iai​​。
    第三行包含 n−1 n - 1n1 个数,代表每条边的权值 bi b_ibi​​,第 i ii 号边是由第 i+12 frac{i + 1}{2}2i+1​​ 号点连向第 i+1 i + 1i+1 号点的边。

    输出格式

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

    样例

    样例输入

    3
    5 1 2
    2 1

    样例输出

    5

    数据范围与提示

    1≤N≤2×105,1<Ai,Bi≤105 1 leq N leq 2 imes 10 ^ 5, 1 < A_i, B_i leq 10 ^ 51N2×105​​,1<Ai​​,Bi​​105​​

      a[x]表示x结点的权值;b[x]表示x结点到其父亲的边权;l[x]表示x的深度,令l[x]==1;d[x]表示x到根的距离;

      f[x][y]表示走完x及其子树再走到y的最小代价。考虑转移方式,如果x是叶子节点,那么答案就是a[y]*distance(x,y);如果x只有左孩子,就先遍历左子树,状态转移是a[lc]*b[lc]+f[lc][y];如果两个孩子都有,就考虑是先转移到左孩子还是右孩子,f[x][y]=min(a[lc]*b[lc]+f[lc][rc]+f[rc][y],a[rc]*b[rc]+f[rc][lc]+f[lc][y])。

      但是考虑到题目数据很大,这样的转移肯定在时间和空间上都不行。又发现有的x,y是不合法的,比如y肯定不能是x的子节点。由此考虑有意义的x,y,可以发现,如果x有一个祖先p(p包括x),则y是p的兄弟节点,f[x][y]的含义变成了走完x及其子树到深度为y的节点的子节点的最小代价。

      设g[x][i]表示走完x的子树再走到x的深度为i的祖先的最小代价。转移: 叶子:g[x][i]=a[y]*(d[x]-d[y]) 只有左孩子:g[x][i]=g[lc][i]+a[lc]*b[lc] 左右孩子都有:g[x][i]=min(a[lc]*b[lc]+f[lc][l[x]]+g[rc][i],a[rc]*b[rc]+f[rc][l[x]]+g[lc][i])。

      最后就是统计答案了,我们选定一个节点x作为第一个点亮的灯,然后统计其子树的答案,再走到x的父节点,再走x的兄弟节点......以此类推。

      由于f[][]和g[][]的第一维都是n,第二维都是logn,所以总的时间复杂度是O(nlogn)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 200010
    using namespace std;
    int n,l[maxn],r[maxn],dep[maxn];
    long long f[maxn][20],b[maxn][20],a[maxn],lval[maxn],rval[maxn],dis[maxn];
    int main(){
        scanf("%d",&n);
        long long v;int rt;dep[1]=1;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<n;i++){
            cin>>v;
            rt=(i+1)>>1,dep[i+1]=dep[rt]+1;
            if((i+1)&1){
                r[rt]=i+1;rval[rt]=v;
                dis[r[rt]]=dis[rt]+rval[rt];
            }
            else {
                l[rt]=i+1;lval[rt]=v;
                dis[l[rt]]=dis[rt]+lval[rt];
            }
        }
        for(int i=n;i>1;i--){
            for(int j=2;j<=dep[i];j++){
                if(!r[i]){
                    if(!l[i]){
                        int fa=i>>(dep[i]-j+1),fab=(i>>(dep[i]-j))^1;
                        b[i][j]=(dis[i]+dis[fab]-(dis[fa]<<1))*a[fab];
                    }
                    else b[i][j]=lval[i]*a[l[i]]+b[l[i]][j];
                }
                else b[i][j]=min(lval[i]*a[l[i]]+b[l[i]][dep[i]+1]+b[r[i]][j],rval[i]*a[r[i]]+b[r[i]][dep[i]+1]+b[l[i]][j]);
            }
        }
        for(int i=n;i>=1;i--){
            for(int j=0;j<=dep[i];j++){
                if(!r[i]){
                    if(!l[i]){
                        if(!j)f[i][j]=0;
                        else {
                            int fa=i>>(dep[i]-j);
                            f[i][j]=(dis[i]-dis[fa])*a[fa];
                        }
                    }
                    else f[i][j]=lval[i]*a[l[i]]+f[l[i]][j];
                }
                else f[i][j]=min(lval[i]*a[l[i]]+b[l[i]][dep[i]+1]+f[r[i]][j],rval[i]*a[r[i]]+b[r[i]][dep[i]+1]+f[l[i]][j]);
            }
        }
        long long ans=f[1][0];
        for(int i=2;i<=n;i++){
            int u=i,bro=u^1;
            long long tmp=f[u][dep[u]-1];
            while(u>1){
                if(bro>n)tmp+=a[u>>2]*(dis[u>>1]-dis[u>>2]);
                else tmp+=a[bro]*(dis[bro]-dis[u>>1])+f[bro][dep[u>>1]-1];
                u>>=1;bro=u^1;
            }
            ans=min(ans,tmp);
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 15—Anomaly Detection异常检测
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 14—Dimensionality Reduction 降维
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 13—Clustering 聚类
    【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 12—Support Vector Machines 支持向量机
    【原】机器学习公开课 目录(课程笔记、测验习题答案、编程作业源码)...持续更新...
    【原】Coursera—Andrew Ng机器学习—Week 11 习题—Photo OCR
    【原】Coursera—Andrew Ng机器学习—Week 10 习题—大规模机器学习
    【原】Coursera—Andrew Ng机器学习—Week 9 习题—异常检测
    【原】Coursera—Andrew Ng机器学习—Week 8 习题—聚类 和 降维
    【原】Coursera—Andrew Ng机器学习—Week 7 习题—支持向量机SVM
  • 原文地址:https://www.cnblogs.com/thmyl/p/8885496.html
Copyright © 2011-2022 走看看