#include<bits/stdc++.h>
using namespace std;
long long w[100007],sum[100007];
int fa[100007],degree[100007],dp[100007],depth[100007];
int flag[100007];
int vis[100007];
using namespace std;
long long w[100007],sum[100007];
int fa[100007],degree[100007],dp[100007],depth[100007];
int flag[100007];
int vis[100007];
int find_x(int x)//非递归并查集
{
int k, j, r;
r = x;
while(r != dp[r]) //查找根节点
r = dp[r]; //找到根节点,用r记录下
k = x;
while(k != r) //非递归路径压缩操作
{
j = dp[k]; //用j暂存parent[k]的父节点
dp[k] = r; //fa[x]指向根节点
k = j; //k移到父节点
}
return r; //返回根节点的值
}
{
int k, j, r;
r = x;
while(r != dp[r]) //查找根节点
r = dp[r]; //找到根节点,用r记录下
k = x;
while(k != r) //非递归路径压缩操作
{
j = dp[k]; //用j暂存parent[k]的父节点
dp[k] = r; //fa[x]指向根节点
k = j; //k移到父节点
}
return r; //返回根节点的值
}
int main(){
int n,l;
long long s;
scanf("%d%d%lld",&n,&l,&s);
for(int i=1;i<=n;i++){
scanf("%lld",&w[i]);
if(w[i]>s)//这个权重超重
return puts("-1"),0;
}
for(int i=2;i<=n;i++){
scanf("%d",&fa[i]);
degree[fa[i]]++;//双亲结点度数+1
}
for(int i=1;i<=n;i++){
dp[i]=i;
depth[i]=depth[fa[i]]+1;//深度为双亲结点深度+1
sum[i]=sum[fa[i]]+w[i];//这一点的总权重为双亲结点总权重+自己权重
}
int h=0,cnt=0,ans=0;
for(int i=1;i<=n;i++){
if(!degree[i])//i为叶子节点
flag[cnt++]=i;//记录叶子节点位置
}
while(h<cnt){
int x=flag[h++];
if(vis[x])
continue;
ans++;
int num=0;
long long val=0;
while(x){
int next=find_x(x);//第一次是自己,之后是祖先(它被合并入它的双亲)
if(vis[next]==1)//当它变成祖先时,这个向上贪心的点已经被选中
break;//这句去掉一样能过,多跑15ms,感觉加上比较好
num+=depth[x]-depth[next]+1;//这一条路的节点数
val+=sum[x]-sum[next]+w[next];////这一条路的总权重
if(num>l||val>s)//超长或者超重就停止,无法继续贪心
break;
vis[next]=1;//这个节点已经被选中,所有的点都只能被选中一次
degree[fa[next]]--;//next的双亲结点度数减一
if(!degree[fa[next]])//如果nect的双亲结点成为叶子节点
flag[cnt++]=fa[next];//记录它的位置
dp[next]=find_x(fa[dp[next]]);//把这个点并到它父亲里
x=fa[next];//贪心它的父亲
}
}
printf("%d ",ans);
return 0;
}
/*while(h<t)
{
int x=q[h++];
if(vis[x]) continue;
++Ans;
int n,l;
long long s;
scanf("%d%d%lld",&n,&l,&s);
for(int i=1;i<=n;i++){
scanf("%lld",&w[i]);
if(w[i]>s)//这个权重超重
return puts("-1"),0;
}
for(int i=2;i<=n;i++){
scanf("%d",&fa[i]);
degree[fa[i]]++;//双亲结点度数+1
}
for(int i=1;i<=n;i++){
dp[i]=i;
depth[i]=depth[fa[i]]+1;//深度为双亲结点深度+1
sum[i]=sum[fa[i]]+w[i];//这一点的总权重为双亲结点总权重+自己权重
}
int h=0,cnt=0,ans=0;
for(int i=1;i<=n;i++){
if(!degree[i])//i为叶子节点
flag[cnt++]=i;//记录叶子节点位置
}
while(h<cnt){
int x=flag[h++];
if(vis[x])
continue;
ans++;
int num=0;
long long val=0;
while(x){
int next=find_x(x);//第一次是自己,之后是祖先(它被合并入它的双亲)
if(vis[next]==1)//当它变成祖先时,这个向上贪心的点已经被选中
break;//这句去掉一样能过,多跑15ms,感觉加上比较好
num+=depth[x]-depth[next]+1;//这一条路的节点数
val+=sum[x]-sum[next]+w[next];////这一条路的总权重
if(num>l||val>s)//超长或者超重就停止,无法继续贪心
break;
vis[next]=1;//这个节点已经被选中,所有的点都只能被选中一次
degree[fa[next]]--;//next的双亲结点度数减一
if(!degree[fa[next]])//如果nect的双亲结点成为叶子节点
flag[cnt++]=fa[next];//记录它的位置
dp[next]=find_x(fa[dp[next]]);//把这个点并到它父亲里
x=fa[next];//贪心它的父亲
}
}
printf("%d ",ans);
return 0;
}
/*while(h<t)
{
int x=q[h++];
if(vis[x]) continue;
++Ans;
int num=0; LL s=0;
while(x)
{
int nxt=Find(x);
num+=depth[x]-depth[nxt]+1, s+=sum[x]-sum[nxt]+w[nxt];
if(num>L||s>S) break;
while(x)
{
int nxt=Find(x);
num+=depth[x]-depth[nxt]+1, s+=sum[x]-sum[nxt]+w[nxt];
if(num>L||s>S) break;
vis[nxt]=1;
if(!--dgr[fa[nxt]]) q[t++]=fa[nxt];
F[nxt]=Find(fa[F[nxt]]), x=fa[nxt];
}
}
printf("%d ",Ans);*/
if(!--dgr[fa[nxt]]) q[t++]=fa[nxt];
F[nxt]=Find(fa[F[nxt]]), x=fa[nxt];
}
}
printf("%d ",Ans);*/