bzoj4027: [HEOI2015]兔子与樱花

传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=4027

思路:自底向上贪心。

设f[i]表示i的子树中最多能删多少点,

g[i]表示i的子树删去f[i]个点后的重量。

每次给儿子按g[son[i]]排序,贪心地从小到大删,直到不能删。

为什么可以这样做?

因为删下面的比删上面的点不会更差,

如果因为按贪心删了儿子而导致这个点不能再删,那么我们只会损失一个点,就是该点。

而删除儿子至少会删除一个,所以不会亏。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=2000010,maxm=maxn<<1;
using namespace std;
int n,m,pre[maxm],now[maxn],son[maxm],tot,c[maxn],a[maxn],ans;
bool ok;char ch;
void read(int &x){
	for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
	for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
	if (ok) x=-x;
}
void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
void dfs(int x){
	for (int y=now[x];y;y=pre[y]) dfs(son[y]);
	int cnt=0;
	for (int y=now[x];y;y=pre[y]) a[++cnt]=c[son[y]];
	sort(a+1,a+1+cnt);
	for (int i=1;i<=cnt;i++){
		if (c[x]+a[i]-1>m) break;
		c[x]+=(a[i]-1),ans++;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) read(c[i]);
	for (int i=1,x,num;i<=n;i++){
		read(num),c[i]+=num;
		for (int j=1;j<=num;j++) read(x),x++,add(i,x);
	}
	dfs(1),printf("%d\n",ans);
	//for (int i=1;i<=n;i++) printf("%d %d %d\n",i,f[i],g[i]);
	return 0;
}


转载于:https://www.cnblogs.com/thythy/p/5493503.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值