树形dp模板题
首先建一个虚拟节点0,让原本的森林变成一颗树。
然后我们设dp[i][j]表示以i为根的子树中,选j门课的最大价值。
转移时我们枚举当前以x为根的子树选课的数量(t),以及分配给x的子节点y多少节课(j)。
不难写出方程:dp[x][t]=max(dp[x][t],dp[x][t-j]+dp[y][j]);

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=510;
const ll INF=2147483647;
ll n,m,s,a[maxn],dp[maxn][maxn];
vector<ll> e[maxn];
void work(ll x){
    dp[x][0]=0;
    for(int i=0;i<e[x].size();i++){
        work(e[x][i]);
        for(int t=m;t>=0;t--){
            for(int j=t;j>=0;j--){
                dp[x][t]=max(dp[x][t],dp[x][t-j]+dp[e[x][i]][j]);
            }
        }
    }
    if(x){//x不为0时,选修x需要占用一门课,获得相应学分.
        for(int i=m;i>0;i--){
            dp[x][i]=dp[x][i-1]+a[x];
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>s>>a[i];
        if(s==0)e[0].push_back(i);//虚拟节点
        else e[s].push_back(i);
    }
    work(0);
    cout<<dp[0][m];
    return 0;
}