/* 树形DP 根节点一定有人 然后 剩下的人没到每个孩子去 因为孩子数可能很多 不好枚举 所以转二叉树 分两部分 O(sum)就可以了 当然 转二叉树候必须顾及原来树的一些性质 如不能只选左孩子 转化好了之后就是DP了 写的记忆化 递归每个节点 枚举分给左右孩子的人数 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 1010 using namespace std; int n,m,son[maxn][3]; int f[maxn][maxn],a[maxn],ans; int DP(int k,int sum)//到节点k时 还剩sum个人没有用 { int i,maxx=0; if(f[k][sum]!=0)return f[k][sum];//记忆化 if(k==0||sum==0)return 0;//剪枝 f[k][sum]=a[k];//先整一个人在k处 for(i=1;i<=sum;i++)//枚举给左孩子多少人 i-1 { if(DP(son[k][2],i-1)+a[k]+DP(son[k][1],sum-i)>maxx) maxx=DP(son[k][2],i-1)+a[k]+DP(son[k][1],sum-i); if(DP(son[k][2],i)>maxx)maxx=DP(son[k][2],sum);//特殊情况 不要k 只要右孩子 //因为这是多叉树转化来的 所以可以实现相反的 不能只要左孩子 因为左孩子和k连在一起 } if(f[k][sum]<maxx) f[k][sum]=maxx; return f[k][sum]; } int main() { cin>>n>>m; int i,x,y; for(i=1;i<=n;i++)cin>>a[i]; for(i=1;i<=n;i++) { cin>>x>>y; if(son[x][1]==0)son[x][1]=y; else { int fa=son[x][1]; while(son[fa][2])fa=son[fa][2]; son[fa][2]=y; } } ans=DP(son[0][1],m); cout<<ans; return 0; }