您的位置:首页 > 其它

bzoj4027: [HEOI2015]兔子与樱花

2015-10-29 09:50 316 查看
传送门: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: