• Jzoj5426 摘Galo


    0v0在野外看到了一棵Galo树,看到食物的0v0瞪大了眼睛,变成了OvO。
    这棵Galo树可以看做是一棵以1号点为根的n个点的有根数,除了根节点以外,每个节点i都有一个Galo,美味度为w[i]。
    OvO发现,如果她摘下了i号Galo,那么i的子树中的Galo以及i到根的路径上的其他Galo都会死掉。
    OvO的袋子只能装k个Galo,她的嘴巴里还能叼1个,请问她所摘Galo的美味度之和的最大值是多少?

    基本树形背包,设f[i][j]表示以i为根的子树,选了j个galo的最大美味度

    那么,f[i][j]=max(f[i][k],f[v][j-k]),f[i][1]=max(f[i][1],w[i])

    注意两个优化

    1.题目中的n,k限制比较诡异:n*k<=10^7

    于是这道题f不能直接开要开成一维的,访问f[i][j]要变成f[ik+j]

    2.树形背包直接做是会T的,要么跑出dfs序变成序列做法,或者是减少背包状态

    我们令size'[x]表示以x为根的叶子结点个数

    那么显然多过size'[x]的部分是可以不用的,这样就可以防止别人用几条链的数据来卡你

    #include<vector>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 100010
    #define f(i,j) F[inv[i]+j-1]
    using namespace std;
    vector<int> s[N];
    int n,_k,val[N]={0},sz[N],inv[N];
    long long F[N*200];
    int dfs(int x){
    	sz[x]=0;
    	if(s[x].size()==0){
    		f(x,0)=0;
    		f(x,1)=val[x];
    		return ++sz[x];
    	}
    	for(int v,i=0,z=s[x].size();i<z;++i){
    		sz[x]+=dfs(v=s[x][i]);
    		for(int j=min(_k,sz[x]);j;--j)
    			for(int k=min(j,sz[v]);k;--k)
    				f(x,j)=max(f(x,j),f(x,j-k)+f(v,k));
    	}
    	f(x,1)=max(f(x,1),(long long)val[x]);
    	return sz[x];
    }
    int main(){
    	freopen("galo.in","r",stdin);
    	freopen("galo.out","w",stdout);
    	scanf("%d%d",&n,&_k); ++_k; _k=min(n,_k);
    	for(int i=1;i<=n;++i) inv[i]=(_k+1)*i;
    	for(int x,y,i=2;i<=n;++i){
    		scanf("%d%d",&x,val+i);
    		s[x].push_back(i); 
    	}
    	dfs(1);
    	for(int i=1;i<=_k;++i) F[0]=max(F[0],f(1,i));
    	printf("%lld
    ",*F);
    }

  • 相关阅读:
    BZOJ3781 小B的询问
    BZOJ3757 苹果树
    BZOJ1491 [NOI2007]社交网络
    BZOJ3754 Tree之最小方差树
    BZOJ1251 序列终结者
    BZOJ2259 [Oibh]新型计算机
    BZOJ1043 [HAOI2008]下落的圆盘
    D. 预定义变量
    A. 变量命名原则
    B. PHP变量的特点
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477218.html
Copyright © 2020-2023  润新知