题目大意:给定一棵有根树,每个点上有一些樱花,现在要求删除一些节点,删除节点的樱花和子节点都会连到父节点上,要求每个节点的樱花数+子节点数不超过
m
,求最多删多少个节点
这数据范围也只能贪心了吧= =
令
fi
为以节点
i
为根的子树中能删除的最多节点(
i
节点不删),
gi
为删除最多节点的情况下
i
号节点的最小负重
那么首先对于每个节点我们对于所有的子节点为根的子树尽量删,然后考虑如何删除子节点
对于节点
x
以及
x
的子节点
y
,若删除
y
节点,对
gx
的贡献为
gy?1
因此我们对
x
节点的所有子节点按
gy?1
排序,从小到大取即可
为什么这是对的呢?
我们考虑一棵子树对父节点的影响只有删除子树的根时根上的东西会被塞到父节点上去
那么一棵子树如果删的不是最多,那么能产生的好处只有删除根时塞到父亲节点上的东西少一些
这样做的最终收益只有【根节点由不可删变为可删】
结果我还莫不如不删根节点,然后让子树中多删一些呢= =
因此贪心是对的。
#include
#include
#include
#include
#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<