可能做了假题。。。一开始想二维树形dp,结果发现nm乘起来肯定会挂,然后继续膜hzwer学长的代码,发现是道瓜题。。。
考虑这样一个结论,下面删点肯定不上面删点优:
如果一个节点x其子节点可以被删去,那么至少可以删去一个点,贡献至少为1,而对于x的父节点毫无影响;而若删去x节点,从对答案的贡献上来讲也是1,不会更优,而会让父节点的剩余空间更小,一定不如删去x子节点优。
由是从下向上贪心,每次将子节点排序,选择删去代价最小的子节点,总复杂度为O(nlogn)
(贪心策略在考场上根本想不到好吗。。。)
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=2000005;
int n,m,ans;
int c[maxn];
vector<int>son[maxn];
bool cmp(int a,int b)
{
return c[a]<c[b];
}
void dfs(int x)
{
int sz=son[x].size();
for(int i=0;i<sz;i++)
dfs(son[x][i]);
sort(son[x].begin(),son[x].end(),cmp);
for(int i=0;i<sz;i++)
{
if(c[x]+c[son[x][i]]-1<=m)
{
c[x]+=c[son[x][i]]-1;
ans++;
}
else break;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0,tmp;i<n;i++)
scanf("%d",c+i);
for(int i=0,tmp,temp;i<n;i++)
{
scanf("%d",&tmp);
c[i]+=tmp;
while(tmp--)
{
scanf("%d",&temp);
son[i].push_back(temp);
}
}
dfs(0);
cout<<ans;
return 0;
}