目录
显示
题目链接
https://www.luogu.com.cn/problem/P4107
题解
定义删除一个点 \(u\) 的代价为:\(son(u)+a_u-1\)。
一种比较显然的做法是:对于每个点 \(u\),贪心地先删代价较小的儿子。
但有个问题:会不会出现删除 \(u\) 本身比删除 \(u\) 的儿子节点更优的情况呢?
其实不会。表面上看我们因为删除了 \(u\) 的儿子节点,导致可能不能再删除 \(u\),但是这一操作只让我们少删了最多一个点。而如果能删除子节点的话,至少可以删掉一个子节点。可见我们的贪心策略不会导致最优解的丢失。
#include <iostream> #include <algorithm> #include <vector> using namespace std; vector<int> e[2000005]; int son[2000005],a[2000005],l[2000005],r[2000005],id[2000005]; int ans,n,m,cnt; bool cmp(int x,int y) { return son[x]+a[x]<son[y]+a[y]; } void dfs(int u) { if(!son[u])return; for(auto v:e[u]) dfs(v); sort(id+l[u],id+r[u]+1,cmp); for(int i=l[u];i<=r[u];i++) { int v=id[i]; if(son[u]+a[u]+son[v]+a[v]-1<=m) { son[u]+=son[v]-1; a[u]+=a[v]; ans++; } } return; } int main() { ios::sync_with_stdio(false); cin>>n>>m; for(int i=0;i<n;i++) cin>>a[i]; for(int i=0;i<n;i++) { cin>>son[i]; l[i]=cnt+1,r[i]=cnt+son[i]; for(int j=1;j<=son[i];j++) { int x; cin>>x; id[++cnt]=x; e[i].push_back(x); } } dfs(0); cout<<ans<<endl; return 0; }