题目大意:给定一棵有根树,每个点上有一些樱花,现在要求删除一些节点,删除节点的樱花和子节点都会连到父节点上,要求每个节点的樱花数+子节点数不超过
这数据范围也只能贪心了吧= =
令
那么首先对于每个节点我们对于所有的子节点为根的子树尽量删,然后考虑如何删除子节点
对于节点
因此我们对
为什么这是对的呢?
我们考虑一棵子树对父节点的影响只有删除子树的根时根上的东西会被塞到父节点上去
那么一棵子树如果删的不是最多,那么能产生的好处只有删除根时塞到父亲节点上的东西少一些
这样做的最终收益只有【根节点由不可删变为可删】
结果我还莫不如不删根节点,然后让子树中多删一些呢= =
因此贪心是对的。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 2002002
using namespace std;
struct abcd{
int to,next;
}table[M];
int head[M],tot;
int n,m;
int a[M],f[M],g[M];
bool not_root[M];
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void Tree_Greedy(int x)
{
int i,top=0;
for(i=head[x];i;i=table[i].next)
{
Tree_Greedy(table[i].to);
f[x]+=f[table[i].to];
g[x]++;
}
static int stack[M];
g[x]+=a[x];
for(i=head[x];i;i=table[i].next)
stack[++top]=g[table[i].to]-1;
sort(stack+1,stack+top+1);
for(i=1;i<=top;i++)
if(g[x]+stack[i]<=m)
f[x]++,g[x]+=stack[i];
else
break;
}
int main()
{
int i,j,k,x;
cin>>n>>m;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
{
scanf("%d",&k);
for(j=1;j<=k;j++)
{
scanf("%d",&x);
Add(i,++x);
not_root[x]=true;
}
}
for(i=1;i<=n;i++)
if(!not_root[i])
{
Tree_Greedy(i);
cout<<f[i]<<endl;
return 0;
}
return 0;
}
原文地址:http://blog.csdn.net/popoqqq/article/details/45506739