```go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
var scanner *bufio.Scanner
func init() {
scanner = bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
buf := make([]byte, 1024*1024)
scanner.Buffer(buf, bufio.MaxScanTokenSize)
}
func nextInt() int {
scanner.Scan()
res := 0
for _, b := range scanner.Bytes() {
res = res*10 + int(b-'0')
}
return res
}
type Edge struct {
to, weight int
}
type Node struct {
up, down, d int
}
var (
M int
pow10 []int64
inv10 []int64
ans int64
adj [][]Edge
deleted []bool
sz []int
)
func extGCD(a, b int64) (int64, int64, int64) {
if b == 0 {
return a, 1, 0
}
gcd, x1, y1 := extGCD(b, a%b)
x := y1
y := x1 - (a/b)*y1
return gcd, x, y
}
func modInverse(n, m int64) int64 {
if m == 1 {
return 0
}
_, x, _ := extGCD(n, m)
return (x%m + m) % m
}
func getSizes(u, p int) int {
sz[u] = 1
for _, edge := range adj[u] {
v := edge.to
if v != p && !deleted[v] {
sz[u] += getSizes(v, u)
}
}
return sz[u]
}
func getCentroid(u, p, total int) int {
for _, edge := range adj[u] {
v := edge.to
if v != p && !deleted[v] && sz[v] > total/2 {
return getCentroid(v, u, total)
}
}
return u
}
func dfs(u, p, d, up, down int, list *[]Node) {
*list = append(*list, Node{up, down, d})
for _, edge := range adj[u] {
v := edge.to
if v != p && !deleted[v] {
w := edge.weight
nextD := d + 1
nextUp := int((int64(w)*pow10[d] + int64(up)) % int64(M))
nextDown := int((int64(down)*10 + int64(w)) % int64(M))
dfs(v, u, nextD, nextUp, nextDown, list)
}
}
}
func count(list []Node) int {
ups := make([]int, len(list))
for i, item := range list {
ups[i] = item.up
}
sort.Ints(ups)
res := 0
for _, item := range list {
val := (int64(-item.down) * inv10[item.d]) % int64(M)
if val < 0 {
val += int64(M)
}
target := int(val)
l := sort.SearchInts(ups, target)
if l < len(ups) && ups[l] == target {
r := sort.SearchInts(ups, target+1)
res += r - l
}
}
return res
}
func solve(u int) {
total := getSizes(u, -1)
centroid := getCentroid(u, -1, total)
listAll := make([]Node, 0, total)
listAll = append(listAll, Node{0, 0, 0})
for _, edge := range adj[centroid] {
v := edge.to
if !deleted[v] {
listV := make([]Node, 0)
nextD := 1
nextUp := edge.weight % M
nextDown := edge.weight % M
dfs(v, centroid, nextD, nextUp, nextDown, &listV)
ans -= int64(count(listV))
listAll = append(listAll, listV...)
}
}
ans += int64(count(listAll))
ans -= 1
deleted[centroid] = true
for _, edge := range adj[centroid] {
v := edge.to
if !deleted[v] {
solve(v)
}
}
}
func main() {
n := nextInt()
M = nextInt()
pow10 = make([]int64, n+1)
inv10 = make([]int64, n+1)
pow10[0] = 1
inv10[0] = 1
inv10_1 := modInverse(10, int64(M))
for i := 1; i <= n; i++ {
pow10[i] = (pow10[i-1] * 10) % int64(M)
inv10[i] = (inv10[i-1] * inv10_1) % int64(M)
}
adj = make([][]Edge, n)
for i := 0; i < n-1; i++ {
u := nextInt()
v := nextInt()
w := nextInt()
adj[u] = append(adj[u], Edge{v, w})
adj[v] = append(adj[v], Edge{u, w})
}
deleted = make([]bool, n)
sz = make([]int, n)
solve(0)
fmt.Println(ans)
}
```