1 条题解

  • 0
    @ 2025-8-24 22:02:22

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zero4338
    **

    搬运于2025-08-24 22:02:22,当前版本为作者最后更新于2021-07-21 08:10:52,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Solution

    当我们固定一个起点后 , 把起点作为整个树的根 , 那么这时每个节点选不选的价值就是它所有儿子的铁球数量加和 .
    那么设 fi,jf_{i,j} 表示在 ii 子树里选择了 jj 个点所能得到的最大贡献 , 转移时考虑这个节点是否选择 .
    sonison_i 表示 ii 节点的儿子 , viv_i 表示 ii 节点的所有儿子铁球数量和 . fi,j=max(fsoni,j,fsoni,j1+vi)f_{i,j}=\max(f_{son_i,j},f_{son_i,j-1}+v_i) 枚举起点作为根 , 复杂度 O(n2v)O(n^2v).
    不能通过本题 ,
    考虑沿用上面对价值的定义 , 设计新的 dp,
    fi,j,0/1,gi,j,0/1f_{i,j,0/1},g_{i,j,0/1} 分别表示从 ii(ii的子树)走到 ii 的子树(ii)中 , ii 被/不被)选 , 选了 jj 个的最大贡献 .
    设当前节点为 uu , 儿子为 sonson, 父亲为 fafa , 当前节点儿子权值和为 vv , 点 ii 的铁球数量为 pip_i.
    那么有转移
    fu,j,0=max(fson,j,0,fson,j,1)f_{u,j,0}=\max(f_{son,j,0},f_{son,j,1})
    $f_{u,j,1}=\max(\max(f_{son,j-1,0},f_{son,j-1,1})+v)$
    gu,j,0=max(gson,j,0,gson,j,1)g_{u,j,0}=\max(g_{son,j,0},g_{son,j,1})
    $g_{u,j,1}=\max(\max(g_{son,j-1,0},g_{son,j-1,1})+v+p_{fa}-p_{son})$
    注意路径方向的不同导致的价值变化 .
    还要考虑 uu 自己作为起点 ,
    gu,1,1=max(v+pfa)g_{u,1,1}=\max(v+p_{fa})
    但直接使用一个点的 ffgg 去更新答案 , 无法保证路径不重复 ,
    那么考虑在合并子树时更新答案 , $ans=\max(\max(f_{son,j,0},f_{son,j,1})+\max(g_{u,k,0},g_{u,k,1}))$
    $ans=\max(\max(g_{son,j,0},g_{son,j,1})+\max(f_{u,k,0},f_{u,k,1}+p_{fa}-p_{son}))$
    注意这里 f,gf,g 是由之前的全部儿子转移而来 , 所以能够保证路径不重复 . 注意由于 fu,0,1,gu,0,1f_{u,0,1},g_{u,0,1} 不合法 , 强制赋值负无穷 .
    上式的 j+kvj+k\leq v , 如果枚举 j,kj,k 会有 O(v2)O(v^2) 的复杂度 , 实际上只需维护前缀最大值就可做到 O(v)O(v) 转移 .
    时间复杂度 O(nv)O(nv)

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #define ll long long
    using namespace std;
    int read()
    {
        int ret=0;char c=getchar();
        while(c>'9'||c<'0')c=getchar();
        while(c>='0'&&c<='9')ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
        return ret;
    }
    const int maxn=1e5+5;
    const int maxm=105;
    const ll inf=1e15;
    int n,v;
    ll ans;
    struct graph
    {
        int p[maxn];ll val[maxn];
        int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
        void add(int x,int y){ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
        void link(int x,int y){add(x,y);add(y,x);}
        ll f[maxn][maxm][2],g[maxn][maxm][2];
        void dfs(int u,int fa)
        {
            val[u]=0;
            for(int i=head[u];i;i=nxt[i])
            {
                if(ver[i]==fa)continue;
                dfs(ver[i],u);val[u]+=p[ver[i]];
            }
            f[u][0][1]=g[u][0][1]=-inf;
            g[u][1][1]=max(g[u][1][1],val[u]+p[fa]);
            for(int i=head[u];i;i=nxt[i])
            {
                if(ver[i]==fa)continue;
                ll mx1=0,mx2=0;
                for(int j=v;j>=0;j--)
                {
                    mx1=max(mx1,max(g[u][v-j][0],g[u][v-j][1]));
                    mx2=max(mx2,max(f[u][v-j][0],f[u][v-j][1]+p[fa]-p[ver[i]]));
                    ans=max(ans,max(f[ver[i]][j][0],f[ver[i]][j][1])+mx1);
                    ans=max(ans,max(g[ver[i]][j][0],g[ver[i]][j][1])+mx2);
                }
                for(int j=1;j<=v;j++)
                    f[u][j][0]=max(f[u][j][0],max(f[ver[i]][j][0],f[ver[i]][j][1])),f[u][j][1]=max(f[u][j][1],max(f[ver[i]][j-1][0],f[ver[i]][j-1][1])+val[u]);
                for(int j=1;j<=v;j++)
                    g[u][j][0]=max(g[u][j][0],max(g[ver[i]][j][0],g[ver[i]][j][1])),g[u][j][1]=max(g[u][j][1],max(g[ver[i]][j-1][0],g[ver[i]][j-1][1])+val[u]+p[fa]-p[ver[i]]);
            }
        }
    }o;
    int main()
    {
        n=read();v=read();
        for(int i=1;i<=n;i++)o.p[i]=read();
        for(int i=1;i<=n-1;i++)o.link(read(),read());
        o.dfs(1,0);
        printf("%lld",ans);
        return 0;
    }
    
    • 1

    信息

    ID
    3633
    时间
    4000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者