题意:
就是给你一棵树,你刚开始可以去掉i个点(i ∈ [ 0 , n ] ),然后计算剩余结点的花费,每个结点的花费为这个子树中没有被删的点的权值。那么现在问你不同的i花费分别是多少。
思考:
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2e3+10;
int T,n,m,k;
int va[M];
int cnt[M];
int dp[M][M][2];
vector<int > e[M];
void dfs(int now,int p)
{
cnt[now] = 1;
dp[now][0][0] = 0;
dp[now][1][1] = va[now];
for(auto spot:e[now])
{
if(spot==p) continue;
dfs(spot,now);
}
for(auto spot:e[now])
{
if(spot==p) continue;
for(int i=cnt[now];i>=0;i--)
{
for(int j=0;j<=cnt[spot]&&i+j<=n;j++)
{
dp[now][i+j][1] = min(dp[now][i+j][1],dp[now][i][1]+dp[spot][j][0]);
dp[now][i+j][1] = min(dp[now][i+j][1],dp[now][i][1]+dp[spot][j][1]+va[spot]);
dp[now][i+j][0] = min(dp[now][i+j][0],dp[now][i][0]+dp[spot][j][0]);
dp[now][i+j][0] = min(dp[now][i+j][0],dp[now][i][0]+dp[spot][j][1]);
}
}
cnt[now] += cnt[spot];
}
}
void init()
{
for(int i=0;i<=n;i++)
{
cnt[i] = 0;
e[i].clear();
for(int j=0;j<=n;j++)
dp[i][j][0] = dp[i][j][1] = inf;
}
}
signed main()
{
IOS;
cin>>T;
while(T--)
{
cin>>n;
init();
for(int i=2;i<=n;i++)
{
int x;cin>>x;
e[x].pb(i);
}
for(int i=1;i<=n;i++) cin>>va[i];
dfs(1,0);
for(int i=0;i<=n;i++) cout<<min(dp[1][n-i][0],dp[1][n-i][1])<<" ";
cout<<"\n";
}
return 0;
}