【BZOJ4027】[HEOI2015]兔子与樱花
Description
很久很久之前,森林里住着一群兔子。有一天,兔子们突然决定要去看樱花。兔子们所在森林里的樱花树很特殊。樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它看成一个有根树结构,其中0号节点是根节点。这个树的每个节点上都会有一些樱花,其中第i个节点有c_i朵樱花。樱花树的每一个节点都有最大的载重m,对于每一个节点i,它的儿子节点的个数和i节点上樱花个数之和不能超过m,即son(i) + c_i <= m,其中son(i)表示i的儿子的个数,如果i为叶子节点,则son(i) = 0
现在兔子们觉得樱花树上节点太多,希望去掉一些节点。当一个节点被去掉之后,这个节点上的樱花和它的儿子节点都被连到删掉节点的父节点上。如果父节点也被删除,那么就会继续向上连接,直到第一个没有被删除的节点为止。
现在兔子们希望计算在不违背最大载重的情况下,最多能删除多少节点。
注意根节点不能被删除,被删除的节点不被计入载重。
Input
第一行输入两个正整数,n和m分别表示节点个数和最大载重
第二行n个整数c_i,表示第i个节点上的樱花个数
接下来n行,每行第一个数k_i表示这个节点的儿子个数,接下来k_i个整数表示这个节点儿子的编号
Output
一行一个整数,表示最多能删除多少节点。
Sample Input
10 4
0 2 2 2 4 1 0 4 1 1
3 6 2 3
1 9
1 8
1 1
0
0
2 7 4
0
1 5
0
Sample Output
4
HINT
对于100%的数据,1 <= n <= 2000000, 1 <= m <= 100000, 0 <= c_i <= 1000
数据保证初始时,每个节点樱花数与儿子节点个数之和大于0且不超过m
题解:容易发现,先删除深度大的点一定不会比先删除深度小的点更差,所以从下往上,能删就删,优先删载重小的就行了
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int maxn=2000010; int n,m,ans,cnt; int to[maxn],next[maxn],head[maxn],v[maxn],f[maxn],p[maxn]; int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } bool cmp(int a,int b) { return f[a]<f[b]; } void dfs(int x) { int i; for(i=head[x];i!=-1;i=next[i]) dfs(to[i]); for(p[0]=0,i=head[x];i!=-1;i=next[i]) p[++p[0]]=to[i]; sort(p+1,p+p[0]+1,cmp); for(i=1;i<=p[0];i++) if(f[x]+f[p[i]]-1<=m) f[x]+=f[p[i]]-1,ans++; } int main() { n=rd(),m=rd(); int i,j,a,b; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) v[i]=rd(); for(i=1;i<=n;i++) { a=rd(),f[i]=a+v[i]; for(j=1;j<=a;j++) { b=rd()+1; add(i,b); } } dfs(1); printf("%d",ans); return 0; }
时间: 2024-11-14 11:47:06