```go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
type Edge struct {
to, w int
}
type Path struct {
L, W int
}
var (
adj [][]Edge
deleted []bool
sz []int
ans int64
l, w int
currentPaths []Path
U []int
bit []int
dfs func(v, p, depth, weight int)
)
func init() {
dfs = func(v, p, depth, weight int) {
if depth > l || weight > w {
return
}
currentPaths = append(currentPaths, Path{depth, weight})
for _, edge := range adj[v] {
if edge.to != p && !deleted[edge.to] {
dfs(edge.to, v, depth+1, weight+edge.w)
}
}
}
}
func getSizes(u, p int) int {
sz[u] = 1
for _, e := range adj[u] {
if e.to != p && !deleted[e.to] {
sz[u] += getSizes(e.to, u)
}
}
return sz[u]
}
func getCentroid(u, p, total int) int {
for _, e := range adj[u] {
if e.to != p && !deleted[e.to] && sz[e.to] > total/2 {
return getCentroid(e.to, u, total)
}
}
return u
}
func countPaths(paths []Path, l, w int) int64 {
n := len(paths)
if n <= 1 {
return 0
}
sort.Slice(paths, func(i, j int) bool {
return paths[i].L < paths[j].L
})
if cap(U) < n {
U = make([]int, n)
}
U = U[:n]
for i := 0; i < n; i++ {
U[i] = paths[i].W
}
sort.Ints(U)
unique := 0
for i := 0; i < n; i++ {
if i == 0 || U[i] != U[i-1] {
U[unique] = U[i]
unique++
}
}
U = U[:unique]
getIdx := func(val int) int {
left, right := 0, unique
for left < right {
mid := int(uint(left+right) >> 1)
if U[mid] <= val {
left = mid + 1
} else {
right = mid
}
}
return left
}
if cap(bit) < unique+1 {
bit = make([]int, unique+1)
}
bit = bit[:unique+1]
for i := 0; i <= unique; i++ {
bit[i] = 0
}
add := func(idx, val int) {
for ; idx <= unique; idx += idx & -idx {
bit[idx] += val
}
}
query := func(idx int) int {
sum := 0
for ; idx > 0; idx -= idx & -idx {
sum += bit[idx]
}
return sum
}
R := n - 1
for i := 0; i <= R; i++ {
add(getIdx(paths[i].W), 1)
}
var totalPairs int64 = 0
for i := 0; i < n; i++ {
for R >= 0 && paths[i].L+paths[R].L > l {
add(getIdx(paths[R].W), -1)
R--
}
if R < 0 {
break
}
idx := getIdx(w - paths[i].W)
totalPairs += int64(query(idx))
if paths[i].L*2 <= l && paths[i].W*2 <= w {
totalPairs--
}
}
return totalPairs / 2
}
func decompose(u int) {
total := getSizes(u, -1)
centroid := getCentroid(u, -1, total)
allPaths := make([]Path, 0, total)
allPaths = append(allPaths, Path{0, 0})
for _, e := range adj[centroid] {
if !deleted[e.to] {
currentPaths = currentPaths[:0]
dfs(e.to, centroid, 1, e.w)
ans -= countPaths(currentPaths, l, w)
allPaths = append(allPaths, currentPaths...)
}
}
ans += countPaths(allPaths, l, w)
deleted[centroid] = true
for _, e := range adj[centroid] {
if !deleted[e.to] {
decompose(e.to)
}
}
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
buf := make([]byte, 1024*1024)
scanner.Buffer(buf, bufio.MaxScanTokenSize)
nextInt := func() int {
scanner.Scan()
res := 0
for _, b := range scanner.Bytes() {
res = res*10 + int(b-'0')
}
return res
}
if !scanner.Scan() {
return
}
n := 0
for _, b := range scanner.Bytes() {
n = n*10 + int(b-'0')
}
if n == 0 {
return
}
l = nextInt()
w = nextInt()
adj = make([][]Edge, n)
for i := 1; i < n; i++ {
p := nextInt() - 1
weight := nextInt()
adj[i] = append(adj[i], Edge{p, weight})
adj[p] = append(adj[p], Edge{i, weight})
}
deleted = make([]bool, n)
sz = make([]int, n)
decompose(0)
fmt.Println(ans)
}
```