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

       设f[i][j]为由根进入遍历完i子树,最后一个到达的点是j时的最小代价,g[i][j]为由子树内任意一点开始遍历完i子树,最后一个到达的点是j时的最小代价,因为是一棵完全二叉树,状态数量是nlogn的。转移考虑四种走法:根→左子树→右子树;根→右子树→左子树;左子树→根→右子树;右子树→根→左子树 即可。好像和大多数题解不一样,明明感觉这种做法比较显然。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 200010
    #define inf 100000000000000000ll
    int n,a[N],p[N],deep[N],t;
    vector<int> son[N];
    vector<long long> f[N],g[N];
    struct data{int to,nxt,len;
    }edge[N];
    void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
    void dfs(int k)
    {
        int cnt=0;
        for (int i=p[k];i;i=edge[i].nxt)
        {
            cnt++;
            deep[edge[i].to]=deep[k]+edge[i].len;
            dfs(edge[i].to);
            for (int j=0;j<son[edge[i].to].size();j++)
            son[k].push_back(son[edge[i].to][j]);
        }
        son[k].push_back(k);
        if (cnt==0) {f[k].push_back(0);g[k].push_back(0);return;}
        if (cnt==1)
        {
            long long v=inf;
            for (int i=0;i<son[k].size()-1;i++)
            f[k].push_back(f[edge[p[k]].to][i]+1ll*edge[p[k]].len*a[edge[p[k]].to]),
            g[k].push_back(f[k][i]),v=min(v,f[edge[p[k]].to][i]+1ll*(deep[son[edge[p[k]].to][i]]-deep[k])*a[k]);
            f[k].push_back(inf),g[k].push_back(v);
        }
        else
        {
            long long P=inf,Q=inf,X=inf,Y=inf;
            int x=edge[p[k]].to,y=edge[edge[p[k]].nxt].to,w=edge[p[k]].len,v=edge[edge[p[k]].nxt].len;
            for (int i=0;i<son[x].size();i++)
            P=min(P,f[x][i]+1ll*w*a[x]+1ll*(deep[son[x][i]]-deep[k])*a[y]),
            X=min(X,g[x][i]+1ll*(deep[son[x][i]]-deep[k])*a[k]);
            for (int i=0;i<son[y].size();i++)
            Q=min(Q,f[y][i]+1ll*v*a[y]+1ll*(deep[son[y][i]]-deep[k])*a[x]),
            Y=min(Y,g[y][i]+1ll*(deep[son[y][i]]-deep[k])*a[k]);
            X=min(X,P),Y=min(Y,Q);
            for (int i=0;i<son[x].size();i++)
            f[k].push_back(Q+1ll*w*a[x]+f[x][i]),g[k].push_back(Y+1ll*w*a[x]+f[x][i]);
            for (int i=0;i<son[y].size();i++)
            f[k].push_back(P+1ll*v*a[y]+f[y][i]),g[k].push_back(X+1ll*v*a[y]+f[y][i]);
            f[k].push_back(inf),g[k].push_back(inf);
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4446.in","r",stdin);
        freopen("bzoj4446.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();
        for (int i=1;i<=n;i++) a[i]=read();
        for (int i=1;i<n;i++) addedge(i+1>>1,i+1,read());
        dfs(1);
        long long ans=inf;
        for (int i=0;i<son[1].size();i++) ans=min(ans,g[1][i]);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    mac下通过复制启动两个tomcat
    搭建一个redis集群
    ubantu系统下永久修改主机名
    民宿项目知识_截取最后一个逗号
    民宿项目知识_string判断是否为空
    民宿项目知识_enum
    民宿项目中的知识点_动态删除tr
    笔记:迁移来自xinlang的笔记
    SVN使用笔记
    iOS性能优化笔记
  • 原文地址:https://www.cnblogs.com/Gloid/p/9874570.html
Copyright © 2011-2022 走看看