#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
//树形DP
//题意: n间房子,m个士兵;每个士兵可以在一个房间里解决20个bug,不足20个也要一个
// 士兵,这些房子是树形结构,每次到达一个房子,必须把它前面的房子里的bug解决
// 了;
// 然后给n个房间的bug数,和解决这些bug得到的利益。
// 然后给的是房间的树形结构。
// 总是从编号为1的房间作为入口。
//解题思路:
// 前向星存图,并不要存成树,存成一个图,还是双向的。
//
struct Node
{
int now,to;
}edge[105];
int cnt,head[105],vis[105];
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
}
void add(int no,int to)
{
edge[cnt].now=no;
edge[cnt].to=head[to];
head[to]=cnt++;
}
int bug[105],p[105];
int n,m;
int dp[105][105];//在i点放j人能得到的最多的能量;
int dfs(int root)
{
vis[root]=1;
int cost = (bug[root]+19)/20;
for(int i=cost;i<=m;i++)
dp[root][i]=p[root];//小于cost的无法获得经验;
for(int i=head[root]; i!=-1; i=edge[i].to)
{
int v=edge[i].now;
if(!vis[v])
{
dfs(v);
for(int j=m;j>=cost;j--)
for(int k=1;j+k<=m;k++)
if(dp[v][k])
dp[root][j+k]= max(dp[root][j+k],dp[root][j]+dp[v][k]);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==-1 && m ==-1)
break;
for(int i=1;i<=n;i++)
scanf("%d%d",&bug[i],&p[i]);
init();
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
if(!m)
{
printf("0\n");
continue;
}
memset(dp,0,sizeof(dp));
dfs(1);
printf("%d\n",dp[1][m]);
}
return 0;
}