#include <bits/stdc++.h>
using namespace std;
int Set(int n, int pos) { return n = n | (1LL << pos); }
int reset(int n, int pos) { return n = n & ~(1LL << pos); }
bool check(int n, int pos) { return (bool)(n & (1LL << pos)); }
int mul(int a, int b) {
  int c;
  c = (a % 1000000007 * b % 1000000007) % 1000000007;
  return c;
}
int add(int a, int b) {
  int c;
  c = (a % 1000000007 + b % 1000000007) % 1000000007;
  return c;
}
int sub(int a, int b) {
  int c;
  c = ((a % 1000000007 - b % 1000000007) % 1000000007 + 1000000007) %
      1000000007;
  return c;
}
int power(int x, int y, int p) {
  int res = 1;
  x = x % p;
  while (y > 0) {
    if (y & 1) res = (res * x) % p;
    y = y >> 1;
    x = (x * x) % p;
  }
  return res;
}
int s2, s1, t2, t1;
int egcd(int a, int b) {
  int temp;
  if (a % b == 0) {
    return s1;
  }
  temp = s2 - (a / b) * s1;
  s2 = s1;
  s1 = temp;
  temp = t2 - (a / b) * t1;
  t2 = t1;
  t1 = temp;
  return egcd(b, a % b);
}
struct node {
  int type, len, we;
  node() {}
  node(int a, int b, int c) {
    type = a;
    len = b;
    we = c;
  }
};
bool cmp(node a, node b) {
  if (a.we == b.we) {
    return a.type < b.type;
  }
  return a.we < b.we;
}
int n, l, w, root;
long long ans;
vector<pair<int, int> > graph[100010];
int son_size[100010], mxson[100010];
bool vis[100010];
int seg[4 * 100010 + 10];
void in_edges() {
  int u, v, c;
  for (int i = 1; i <= n - 1; i++) {
    u = i + 1;
    scanf("%d", &v);
    scanf("%d", &c);
    graph[u].push_back(make_pair(v, c));
    graph[v].push_back(make_pair(u, c));
  }
}
void dfssize(int src, int par) {
  son_size[src] = 1;
  mxson[src] = 0;
  for (int i = 0; i < graph[src].size(); i++) {
    int adj = graph[src][i].first;
    if (adj != par && vis[adj] == 0) {
      dfssize(adj, src);
      son_size[src] += son_size[adj];
      mxson[src] = max(mxson[src], son_size[adj]);
    }
  }
}
void dfsroot(int main_source, int source, int par) {
  if (son_size[main_source] - son_size[source] > mxson[source]) {
    mxson[source] = son_size[main_source] - son_size[source];
  }
  if (mxson[source] < mxson[root]) {
    root = source;
  }
  for (int i = 0; i < graph[source].size(); i++) {
    int adj = graph[source][i].first;
    if (adj != par && vis[adj] == 0) {
      dfsroot(main_source, adj, source);
    }
  }
}
void update(int n, int b, int e, int pos, int val) {
  if (b >= pos && e <= pos) {
    seg[n] += val;
    return;
  }
  if (b > pos || e < pos) {
    return;
  }
  int mid = (b + e) / 2;
  update(n * 2, b, mid, pos, val);
  update(n * 2 + 1, mid + 1, e, pos, val);
  seg[n] = seg[n * 2] + seg[n * 2 + 1];
}
int query(int n, int b, int e, int i, int j) {
  if (e < i || j < b) return 0;
  if (i <= b && e <= j) return seg[n];
  int left = n * 2;
  int right = n * 2 + 1;
  int mid = (b + e) / 2;
  int p1 = query(left, b, mid, i, j);
  int p2 = query(right, mid + 1, e, i, j);
  return p1 + p2;
}
vector<node> lis;
void dfsdis(int src, int par, int length, int cost) {
  if (l - length >= 0 && w - cost >= 0) {
    lis.push_back(node(0, length, cost));
    lis.push_back(node(1, l - length, w - cost));
  }
  for (int i = 0; i < graph[src].size(); i++) {
    int adj = graph[src][i].first;
    int adj_cost = graph[src][i].second;
    if (adj != par && vis[adj] == 0) {
      dfsdis(adj, src, length + 1, cost + adj_cost);
    }
  }
}
void dfs(int source) {
  dfssize(source, -1);
  root = 0;
  mxson[0] = n;
  dfsroot(source, source, -1);
  int now_root = root;
  lis.clear();
  dfsdis(now_root, -1, 0, 0);
  sort(lis.begin(), lis.end(), cmp);
  for (int i = 0; i < (int)lis.size(); i++) {
    if (lis[i].type == 0) {
      update(1, 0 + 1, 100010, lis[i].len + 1, 1);
    } else if (lis[i].type == 1) {
      int now_ans = query(1, 0 + 1, 100010, 0 + 1, lis[i].len + 1);
      ans += (long long)now_ans;
    }
  }
  ans--;
  for (int i = 0; i < (int)lis.size(); i++) {
    if (lis[i].type == 0) {
      update(1, 0 + 1, 100010, lis[i].len + 1, -1);
    }
  }
  for (int i = 0; i < graph[now_root].size(); i++) {
    int adj = graph[now_root][i].first;
    int adj_cost = graph[now_root][i].second;
    if (vis[adj] == 0) {
      lis.clear();
      dfsdis(adj, now_root, 1, adj_cost);
      sort(lis.begin(), lis.end(), cmp);
      for (int i = 0; i < (int)lis.size(); i++) {
        if (lis[i].type == 0) {
          update(1, 0 + 1, 100010, lis[i].len + 1, 1);
        } else if (lis[i].type == 1) {
          int now_ans = query(1, 0 + 1, 100010, 0 + 1, lis[i].len + 1);
          ans -= (long long)now_ans;
        }
      }
      for (int i = 0; i < (int)lis.size(); i++) {
        if (lis[i].type == 0) {
          update(1, 0 + 1, 100010, lis[i].len + 1, -1);
        }
      }
    }
  }
  vis[now_root] = 1;
  for (int i = 0; i < graph[now_root].size(); i++) {
    int adj = graph[now_root][i].first;
    int adj_cost = graph[now_root][i].second;
    if (vis[adj] == 0) {
      dfs(adj);
    }
  }
}
int main() {
  scanf("%d", &n);
  scanf("%d", &l);
  scanf("%d", &w);
  in_edges();
  dfs(1);
  cout << ans / 2 << endl;
  return 0;
}
