JZOJ 5426 Galo

Galo

Description

给出一棵以 1 号点为根的n个点的有根数,除了根节点以外,每个节点 i 都有一个果子,美味度为wi
如果摘下了 i 号果子,那么i的子树中的果子以及 i 到根的路径上的其他果子都会死掉,都不能摘。
最多能摘k个果子,问所摘果子的美味度之和的最大值是多少。

Data Constraint

n *k<= 107
wi <= 105

Solution

经典例题,其实也没什么好讲的,就是树型依赖动态规划。
s [i]表示以 i 为根的子树大小。
d[ i ]表示dfs序的第 i 位的节点。
转移方程式如下
f[ i ][l]= max ( max ( f [i+ 1 ][l], f [i+ s [d[ i ]]][l]), f [i+ s [d[ i ]]][l- 1 ]+w[ d [i]])
不会树型依赖动态规划请点这里
树型依赖动态规划

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define fo(i,j,l) for(int i=j;i<=l;i++)
#define fd(i,j,l) for(int i=j;i>=l;i--)

using namespace std;
typedef long long ll;
const long long N=2e7+2e3,M=N/2;
ll f[N];
int ne[M],lb[M],la[M],s[M],d[M],w[M];
int n,m,j,k,l,i,o,a,b;

void llb(int a,int b)
{ne[++o]=la[a]; la[a]=o; lb[o]=b;}

int de(int a,int b)
{return (a-1)*(k+1)+b+1;}

ll max(ll a,ll b)
{if(a>b)return a;else return b;}

int main()
{
    freopen("galo.in","r",stdin);
    freopen("galo.out","w",stdout);
    cin>>n>>k; int kk=k+1;
    fo(i,2,n){
        scanf("%d%d",&a,&b);
        llb(a,i); w[i]=b;
    }
    int r,t;
    d[k=1]=1;
    s[1]=1;
    s[0]=0;
    for(f[1]=r=1;r;){
        t=f[r];
        s[t]+=s[f[r+1]];
        if(la[t]){
            f[++r]=lb[la[t]]; d[++k]=f[r];
            la[t]=ne[la[t]]; s[f[r]]=1; f[r+1]=0;
        }else r--;
    }
    w[1]=0;
    fo(i,1,n)f[de(i,0)]=0;
    k=kk;
    fd(i,n,1)
    fo(l,1,k)
    f[de(i,l)]=
    max(max(f[de(i+1,l)],f[de(i+s[d[i]],l)]),f[de(i+s[d[i]],l-1)]+w[d[i]]);
    ll ans=0;
    fo(i,1,k)ans=max(ans,f[de(1,i)]);
    printf("%lld",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值