#include <bits/stdc++.h>

#define Max 100005

using namespace std;

inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
    int x=0;char ch=gc();bool positive=1;
    for(;!isdigit(ch);ch=gc())if(ch=='-')positive=0;
    for(;isdigit(ch);ch=gc())x=x*10+ch-'0';
    return positive?x:-x;
}

inline void write(int x){
    if(x<0)x=-x,putchar('-');
    if(x>9)write(x/10);putchar(x%10+'0');
}

inline void writeln(int x){
    write(x);puts("");
}

struct Edge{
    int v,to,w;
}e[Max*2];

struct Node{
    int sum1,sum2,dep;
}stk[Max];

int n,k,l,r,w,sum,ans,top,root,size,son[Max],dis[Max],tot[Max],head[Max];
bool vis[Max];

inline void add(int u,int v,int w){
    e[++size].v=v;e[size].to=head[u];e[size].w=w;head[u]=size;
}

inline void getrt(int u,int fa){
    son[u]=1;
    tot[u]=0;
    for(int i=head[u];i;i=e[i].to){
        int v=e[i].v;
        if(v==fa||vis[v])continue;
        getrt(v,u);
        son[u]+=son[v];
        tot[u]=max(tot[u],son[v]);
    }
    tot[u]=max(tot[u],sum-tot[u]);
    if(tot[u]<tot[root])root=u;
    return;
}

inline int qpow(int x,int y){
    int ans=1;
    while(y){
        if(y&1)ans=ans*x%k;
        x=x*x%k;
        y>>=1;
    }
    return ans;
}

inline void getdis(int u,int fa,int sum1,int sum2,int dep){
    stk[++top].sum1=sum1;
    stk[top].sum2=sum2;
    stk[top].dep=dep;
    for(int i=head[u];i;i=e[i].to){
        int v=e[i].v;
        if(v==fa||vis[v])continue;
        getdis(v,u,(sum1*10+e[i].w)%k,(sum1+qpow(10,dep)*e[i].w)%k,dep+1);
    }
    return;
}

inline int getnow(int l,int r){
    int sum=0;
    if(l>r)return sum;
    for(int i=l;i<=r;i++){
        dis[stk[i].sum2]++;
    }
    for(int i=l;i<=r;i++){
        sum+=dis[(k-stk[i].sum1)*qpow(qpow(10,stk[i].dep),k-2)%k];
    }
    for(int i=l;i<=r;i++){
        dis[stk[i].sum2]--;
    }
    return sum;
}

inline void getans(int u){
    top=0;
    for(int i=head[u];i;i=e[i].to){
        int v=e[i].v;
        if(vis[v])continue;
        int last=top;
        getdis(v,u,e[i].w%k,e[i].w%k,1);
        ans-=getnow(last+1,top);
    }
    ans+=getnow(1,top);
    // cout<<u<<endl;
    for(int i=1;i<=top;i++){
        if(!stk[i].sum1)ans++;
        if(!stk[i].sum2)ans++;
        // cout<<stk[i].sum1<<" "<<stk[i].sum2<<" "<<stk[i].dep<<endl;
    }
    return;
}

inline void getall(int u){
    getans(u);
    vis[u]=true;
    for(int i=head[u];i;i=e[i].to){
        int v=e[i].v;
        if(vis[v])continue;
        root=0;
        sum=son[v];
        getrt(v,u);
        getall(root);
    }
    return;
}

int main(){
    n=read();k=read();
    for(int i=1;i<n;i++){
        l=read()+1;r=read()+1;w=read();
        add(l,r,w);
        add(r,l,w);
    }
    tot[0]=1e9;
    sum=n;
    root=0;
    getrt(1,0);
    getall(root);
    writeln(ans);
    return 0;
}


#include <bits/stdc++.h>

#define ll long long
#define Max 100005

using namespace std;

inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
    ll x=0;char ch=gc();bool positive=1;
    for(;!isdigit(ch);ch=gc())if(ch=='-')positive=0;
    for(;isdigit(ch);ch=gc())x=x*10+ch-'0';
    return positive?x:-x;
}

inline void write(ll x){
    if(x<0)x=-x,putchar('-');
    if(x>9)write(x/10);putchar(x%10+'0');
}

inline void writeln(ll x){
    write(x);puts("");
}

struct Edge{
    ll v,to,w;
}e[Max*2];

struct Node{
    ll sum1,sum2,dep;
}stk[Max];

ll n,k,l,r,w,sum,ans,top,root,size,son[Max],tot[Max],head[Max];
bool vis[Max];
map<int,int>dis;

inline void add(ll u,ll v,ll w){
    e[++size].v=v;e[size].to=head[u];e[size].w=w;head[u]=size;
}

inline void getrt(ll u,ll fa){
    son[u]=1;
    tot[u]=0;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(v==fa||vis[v])continue;
        getrt(v,u);
        son[u]+=son[v];
        tot[u]=max(tot[u],son[v]);
    }
    tot[u]=max(tot[u],sum-tot[u]);
    if(tot[u]<tot[root])root=u;
    return;
}

inline ll qpow(ll x,ll y){
    ll ans=1;
    while(y){
        if(y&1)ans=ans*x%k;
        x=x*x%k;
        y>>=1;
    }
    return ans;
}

inline void getdis(ll u,ll fa,ll sum1,ll sum2,ll dep){
    stk[++top].sum1=sum1;
    stk[top].sum2=sum2;
    stk[top].dep=dep;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(v==fa||vis[v])continue;
        getdis(v,u,(sum1*10+e[i].w)%k,(sum1+qpow(10,dep)*e[i].w)%k,dep+1);
    }
    return;
}

inline void exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1;y=0;
		return;
	}
	exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return;
}

inline ll getnow(ll l,ll r){
    ll sum=0;
    if(l>r)return sum;
    for(ll i=l;i<=r;i++){
        dis[stk[i].sum2]++;
    }
    for(ll i=l;i<=r;i++){
        ll x,y;
        exgcd(qpow(10,stk[i].dep),k,x,y);
        x=(x%k+k)%k;
        // cout<<qpow(10,stk[i].dep)<<" "<<x<<endl;
        sum+=dis[((k-stk[i].sum1*x%k)%k+k)%k];
    }
    for(ll i=l;i<=r;i++){
        dis[stk[i].sum2]--;
    }
    return sum;
}
//sum2*qpow(10,sum1_dep)+sum1=0
//sum2+sum1*qpow(10,-sum1_dep)=0
inline void getans(ll u){
    top=0;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(vis[v])continue;
        ll last=top;
        getdis(v,u,e[i].w%k,e[i].w%k,1);
        ans-=getnow(last+1,top);
    }
    ans+=getnow(1,top);
    // cout<<u<<" ";
    for(ll i=1;i<=top;i++){
        if(!stk[i].sum1)ans++;
        if(!stk[i].sum2)ans++;
        // cout<<stk[i].sum1<<" "<<stk[i].sum2<<" "<<stk[i].dep<<endl;
    }
    // cout<<ans<<endl;
    return;
}

inline void getall(ll u){
    getans(u);
    vis[u]=true;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(vis[v])continue;
        root=0;
        sum=son[v];
        getrt(v,u);
        getall(root);
    }
    return;
}

int main(){
    n=read();k=read();
    // n=100000;k=11;
    for(ll i=1;i<n;i++){
        l=read()+1;r=read()+1;w=read();
        add(l,r,w);
        add(r,l,w);
        add(i,i+1,1);
        add(i+1,i,1);
    }
    tot[0]=1e9;
    sum=n;
    root=0;
    getrt(1,0);
    getall(root);
    writeln(ans);
    return 0;
}


#include <bits/stdc++.h>

#define ll long long
#define Max 100005

using namespace std;

inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
    ll x=0;char ch=gc();bool positive=1;
    for(;!isdigit(ch);ch=gc())if(ch=='-')positive=0;
    for(;isdigit(ch);ch=gc())x=x*10+ch-'0';
    return positive?x:-x;
}

inline void write(ll x){
    if(x<0)x=-x,putchar('-');
    if(x>9)write(x/10);putchar(x%10+'0');
}

inline void writeln(ll x){
    write(x);puts("");
}

struct Edge{
    ll v,to,w;
}e[Max*2];

struct Node{
    ll sum1,sum2,dep;
}stk[Max];

ll n,k,l,r,w,sum,ans,top,root,size,q[Max],son[Max],tot[Max],head[Max];
bool vis[Max];
map<int,int>dis;

inline void add(ll u,ll v,ll w){
    e[++size].v=v;e[size].to=head[u];e[size].w=w;head[u]=size;
}

inline void getrt(ll u,ll fa){
    son[u]=1;
    tot[u]=0;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(v==fa||vis[v])continue;
        getrt(v,u);
        son[u]+=son[v];
        tot[u]=max(tot[u],son[v]);
    }
    tot[u]=max(tot[u],sum-tot[u]);
    if(tot[u]<tot[root])root=u;
    return;
}

inline void getdis(ll u,ll fa,ll sum1,ll sum2,ll dep){
    stk[++top].sum1=sum1;
    stk[top].sum2=sum2;
    stk[top].dep=dep;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(v==fa||vis[v])continue;
        getdis(v,u,(sum1*10+e[i].w)%k,(sum2+q[dep]*e[i].w)%k,dep+1);
    }
    return;
}

inline void exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1;y=0;
		return;
	}
	exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return;
}

inline ll getnow(ll l,ll r){
    ll sum=0;
    if(l>r)return sum;
    dis.clear();
    for(ll i=l;i<=r;i++){
        dis[stk[i].sum2]++;
    }
    for(ll i=l;i<=r;i++){
        ll x,y;
        exgcd(q[stk[i].dep],k,x,y);
        x=(x%k+k)%k;
        sum+=dis[(k-stk[i].sum1)*x%k];
    }
    return sum;
}
//sum2*qpow(10,sum1_dep)+sum1=0
//sum2+sum1*qpow(10,-sum1_dep)=0
inline void getans(ll u){
    top=0;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(vis[v])continue;
        ll last=top;
        getdis(v,u,e[i].w%k,e[i].w%k,1);
        ans-=getnow(last+1,top);
    }
    ans+=getnow(1,top);
    // cout<<u<<" ";
    for(ll i=1;i<=top;i++){
        if(!stk[i].sum1)ans++;
        if(!stk[i].sum2)ans++;
        // cout<<stk[i].sum1<<" "<<stk[i].sum2<<" "<<stk[i].dep<<endl;
    }
    // cout<<ans<<endl;
    return;
}

inline void getall(ll u){
    getans(u);
    vis[u]=true;
    for(ll i=head[u];i;i=e[i].to){
        ll v=e[i].v;
        if(vis[v])continue;
        root=0;
        sum=son[v];
        getrt(v,u);
        getall(root);
    }
    return;
}

int main(){
    n=read();k=read();
    q[0]=1;
    for(ll i=1;i<=n;i++)q[i]=q[i-1]*10%k;
    for(ll i=1;i<n;i++){
        l=read()+1;r=read()+1;w=read();
        add(l,r,w);
        add(r,l,w);
    }
    tot[0]=1e9;
    sum=n;
    root=0;
    getrt(1,0);
    getall(root);
    writeln(ans);
    return 0;
}


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<queue>
#include<iostream>
#define REP(i, n) for(int i = 0, ed_##i = n; i < ed_##i; i++)
#define FOR(i, n) for(int i = 1, ed_##i = n; i <= ed_##i; i++)
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))  // Leading zeros
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#ifdef QWERTIER
#define err(x) cerr << #x << " : " << x << endl
#else
#define err(x)
#endif

typedef long long LL;
using namespace std;

typedef pair<int,int> pii;
#define MP make_pair
#define fi first
#define se second

#define N 100010

int le[N], ev[N<<1], ew[N<<1], pe[N<<1], ecnt;
void addEdge(int u, int v, int w) {
  ecnt++;
  pe[ecnt] = le[u];
  ev[ecnt] = v;
  ew[ecnt] = w;
  le[u] = ecnt;
}

int M;
int fPow(LL t, int p) {
  LL ret = 1;
  while (p) {
    if (p&1)
      ret = ret * t % M;
    t = t * t % M;
    p >>= 1;
  }
  return ret;
}

int mark[N];
int sz[N];
int findCore(int u, int fa, int tot, int &core, int &coreSz) {
  sz[u] = 1;
  int msz = 0;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    findCore(v, u, tot, core, coreSz);
    sz[u] += sz[v];
    msz = max(msz, sz[v]);
  }
  if (max(tot - sz[u], msz) < coreSz) {
    core = u;
    coreSz = max(tot - sz[u], msz);
  }
}

int getSz(int u, int fa) {
  int ret = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    ret += getSz(v, u);
  }
  return ret;
}

void dfs(int u, int fa, int dep, int downv, vector<pii> &down, int upv, map<int, int> &up) {
  down.push_back(MP(downv, dep));
  up[upv]++;

  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v] || fa == v)
      continue;
    //printf(" %d %d\n", u, v);
    dfs(v, u, dep + 1, (downv * (LL)10 + ew[i]) % M, down, (upv + ew[i] * (LL)fPow(10, dep)) % M, up);
  }
}

LL ans = 0;
vector<pii> down[N];
map<int, int> up[N];
void divide(int u) {
  //printf("%d\n", u);
  up[u].clear();
  up[u][0] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    down[v].clear();
    up[v].clear();
    dfs(v, u, 1, ew[i]%M, down[v], ew[i]%M, up[v]);
    for (auto &node : up[v]) {
      //printf("%d %d %d %d\n", u, v, node.fi, node.se);
      up[u][node.fi] += node.se;
    }
  }
  ans += up[u][0] - 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    for (auto &node : down[v]) {
      int inv = (-node.fi%M+M)%M * (LL) fPow(fPow(10, M- 2), node.se) % M;
      //printf("inv:%d %d %d %d %d\n", node.fi, node.se, inv, up[u][inv], up[v][inv]);
      ans += node.se * (LL)(up[u][inv] - (up[v].count(inv)?up[v][inv]:0));
      //printf("ans:%I64d\n", ans);
    }
  }
  mark[u] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    int core = 0, coreSz = 1<<30;
    findCore(v, u, getSz(v, u), core, coreSz);
    divide(core);
  }
}

int main(){
#ifdef QWERTIER
  freopen("in.txt","r",stdin);
#endif
  int n;
  scanf("%d%d", &n, &M);
  FOR (i, n-1) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addEdge(u, v, w);
    addEdge(v, u, w);
  }
  int core, coreSz = 1 << 30;
  findCore(0, -1, n, core, coreSz);
  divide(core);
  printf("%I64d\n", ans);
  return 0;
}


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<queue>
#include<iostream>
#define REP(i, n) for(int i = 0, ed_##i = n; i < ed_##i; i++)
#define FOR(i, n) for(int i = 1, ed_##i = n; i <= ed_##i; i++)
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))  // Leading zeros
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#ifdef QWERTIER
#define err(x) cerr << #x << " : " << x << endl
#else
#define err(x)
#endif

typedef long long LL;
using namespace std;

typedef pair<int,int> pii;
#define MP make_pair
#define fi first
#define se second

#define N 100010

int le[N], ev[N<<1], ew[N<<1], pe[N<<1], ecnt;
void addEdge(int u, int v, int w) {
  ecnt++;
  pe[ecnt] = le[u];
  ev[ecnt] = v;
  ew[ecnt] = w;
  le[u] = ecnt;
}

int M;
int fPow(LL t, int p) {
  LL ret = 1;
  while (p) {
    if (p&1)
      ret = ret * t % M;
    t = t * t % M;
    p >>= 1;
  }
  return ret;
}

int mark[N];
int sz[N];
int findCore(int u, int fa, int tot, int &core, int &coreSz) {
  sz[u] = 1;
  int msz = 0;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    findCore(v, u, tot, core, coreSz);
    sz[u] += sz[v];
    msz = max(msz, sz[v]);
  }
  if (max(tot - sz[u], msz) < coreSz) {
    core = u;
    coreSz = max(tot - sz[u], msz);
  }
}

int getSz(int u, int fa) {
  int ret = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    ret += getSz(v, u);
  }
  return ret;
}

void dfs(int u, int fa, int dep, int downv, vector<pii> &down, int upv, map<int, int> &up) {
  down.push_back(MP(downv, dep));
  up[upv]++;

  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v] || fa == v)
      continue;
    //printf(" %d %d\n", u, v);
    dfs(v, u, dep + 1, (downv * (LL)10 + ew[i]) % M, down, (upv + ew[i] * (LL)fPow(10, dep)) % M, up);
  }
}

LL ans = 0;
vector<pii> down[N];
map<int, int> up[N];
void divide(int u) {
  //printf("%d\n", u);
  up[u].clear();
  up[u][0] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    down[v].clear();
    up[v].clear();
    dfs(v, u, 1, ew[i]%M, down[v], ew[i]%M, up[v]);
    for (auto &node : up[v]) {
      //printf("%d %d %d %d\n", u, v, node.fi, node.se);
      up[u][node.fi] += node.se;
    }
  }
  ans += up[u][0] - 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    for (auto &node : down[v]) {
      int inv = (-node.fi%M+M)%M * (LL) fPow(fPow(10, M- 2), node.se) % M;
      //printf("inv:%d %d %d %d %d\n", node.fi, node.se, inv, up[u][inv], up[v][inv]);
      ans += (up[u][inv] - (up[v].count(inv)?up[v][inv]:0));
      //printf("ans:%I64d\n", ans);
    }
  }
  mark[u] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    int core = 0, coreSz = 1<<30;
    findCore(v, u, getSz(v, u), core, coreSz);
    divide(core);
  }
}

int main(){
#ifdef QWERTIER
  freopen("in.txt","r",stdin);
#endif
  int n;
  scanf("%d%d", &n, &M);
  FOR (i, n-1) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addEdge(u, v, w);
    addEdge(v, u, w);
  }
  if (M == 1) {
    printf("%I64d\n", n*(LL)n/2);
    return 0;
  }
  int core, coreSz = 1 << 30;
  findCore(0, -1, n, core, coreSz);
  divide(core);
  printf("%I64d\n", ans);
  return 0;
}


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<queue>
#include<iostream>
#define REP(i, n) for(int i = 0, ed_##i = n; i < ed_##i; i++)
#define FOR(i, n) for(int i = 1, ed_##i = n; i <= ed_##i; i++)
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))  // Leading zeros
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#ifdef QWERTIER
#define err(x) cerr << #x << " : " << x << endl
#else
#define err(x)
#endif

typedef long long LL;
using namespace std;

typedef pair<int,int> pii;
#define MP make_pair
#define fi first
#define se second

#define N 100010

int le[N], ev[N<<1], ew[N<<1], pe[N<<1], ecnt;
void addEdge(int u, int v, int w) {
  ecnt++;
  pe[ecnt] = le[u];
  ev[ecnt] = v;
  ew[ecnt] = w;
  le[u] = ecnt;
}

int M;
int fPow(LL t, int p) {
  LL ret = 1;
  while (p) {
    if (p&1)
      ret = ret * t % M;
    t = t * t % M;
    p >>= 1;
  }
  return ret;
}

int mark[N];
int sz[N];
int findCore(int u, int fa, int tot, int &core, int &coreSz) {
  sz[u] = 1;
  int msz = 0;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    findCore(v, u, tot, core, coreSz);
    sz[u] += sz[v];
    msz = max(msz, sz[v]);
  }
  if (max(tot - sz[u], msz) < coreSz) {
    core = u;
    coreSz = max(tot - sz[u], msz);
  }
}

int getSz(int u, int fa) {
  int ret = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    ret += getSz(v, u);
  }
  return ret;
}

void dfs(int u, int fa, int dep, int downv, vector<pii> &down, int upv, map<int, int> &up) {
  down.push_back(MP(downv, dep));
  up[upv]++;

  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v] || fa == v)
      continue;
    //printf(" %d %d\n", u, v);
    dfs(v, u, dep + 1, (downv * (LL)10 + ew[i]) % M, down, (upv + ew[i] * (LL)fPow(10, dep)) % M, up);
  }
}

LL ans = 0;
vector<pii> down[N];
map<int, int> up[N];
void divide(int u) {
  printf("%d\n", u);
  up[u].clear();
  up[u][0] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    down[v].clear();
    up[v].clear();
    dfs(v, u, 1, ew[i]%M, down[v], ew[i]%M, up[v]);
    for (auto &node : up[v]) {
      //printf("%d %d %d %d\n", u, v, node.fi, node.se);
      up[u][node.fi] += node.se;
    }
  }
  ans += up[u][0] - 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    for (auto &node : down[v]) {
      int inv = (-node.fi%M+M)%M * (LL) fPow(fPow(10, M- 2), node.se) % M;
      //printf("inv:%d %d %d %d %d\n", node.fi, node.se, inv, up[u][inv], up[v][inv]);
      ans += (up[u][inv] - (up[v].count(inv)?up[v][inv]:0));
      //printf("ans:%I64d\n", ans);
    }
  }
  mark[u] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    int core = 0, coreSz = 1<<30;
    findCore(v, u, getSz(v, u), core, coreSz);
    divide(core);
  }
}

int main(){
#ifdef QWERTIER
  freopen("in.txt","r",stdin);
#endif
  int n;
  scanf("%d%d", &n, &M);
  FOR (i, n-1) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addEdge(u, v, w);
    addEdge(v, u, w);
  }
  int core, coreSz = 1 << 30;
  findCore(0, -1, n, core, coreSz);
  divide(core);
  printf("%I64d\n", ans);
  return 0;
}


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<queue>
#include<iostream>
#define REP(i, n) for(int i = 0, ed_##i = n; i < ed_##i; i++)
#define FOR(i, n) for(int i = 1, ed_##i = n; i <= ed_##i; i++)
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))  // Leading zeros
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#ifdef QWERTIER
#define err(x) cerr << #x << " : " << x << endl
#else
#define err(x)
#endif

typedef long long LL;
using namespace std;

typedef pair<int,int> pii;
#define MP make_pair
#define fi first
#define se second

#define N 100010

int le[N], ev[N<<1], ew[N<<1], pe[N<<1], ecnt;
void addEdge(int u, int v, int w) {
  ecnt++;
  pe[ecnt] = le[u];
  ev[ecnt] = v;
  ew[ecnt] = w;
  le[u] = ecnt;
}

int M;
int fPow(LL t, int p) {
  LL ret = 1;
  while (p) {
    if (p&1)
      ret = ret * t % M;
    t = t * t % M;
    p >>= 1;
  }
  return ret;
}

int mark[N];
int sz[N];
int findCore(int u, int fa, int tot, int &core, int &coreSz) {
  sz[u] = 1;
  int msz = 0;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    findCore(v, u, tot, core, coreSz);
    sz[u] += sz[v];
    msz = max(msz, sz[v]);
  }
  if (max(tot - sz[u], msz) < coreSz) {
    core = u;
    coreSz = max(tot - sz[u], msz);
  }
}

int getSz(int u, int fa) {
  int ret = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    ret += getSz(v, u);
  }
  return ret;
}

void dfs(int u, int fa, int dep, int downv, vector<pii> &down, int upv, map<int, int> &up) {
  down.push_back(MP(downv, dep));
  up[upv]++;

  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v] || fa == v)
      continue;
    //printf(" %d %d\n", u, v);
    dfs(v, u, dep + 1, (downv * (LL)10 + ew[i]) % M, down, (upv + ew[i] * (LL)fPow(10, dep)) % M, up);
  }
}

LL ans = 0;
vector<pii> down[N];
map<int, int> up[N];
void divide(int u) {
  //printf("%d\n", u);
  up[u].clear();
  up[u][0] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    down[v].clear();
    up[v].clear();
    dfs(v, u, 1, ew[i]%M, down[v], ew[i]%M, up[v]);
    for (auto &node : up[v]) {
      //printf("%d %d %d %d\n", u, v, node.fi, node.se);
      up[u][node.fi] += node.se;
    }
  }
  ans += up[u][0] - 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    for (auto &node : down[v]) {
      int inv = (-node.fi%M+M)%M * (LL) fPow(fPow(10, M- 2), node.se) % M;
      //printf("inv:%d %d %d %d %d\n", node.fi, node.se, inv, up[u][inv], up[v][inv]);
      ans += (up[u][inv] - (up[v].count(inv)?up[v][inv]:0));
      //printf("ans:%I64d\n", ans);
    }
  }
  mark[u] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    int core = 0, coreSz = 1<<30;
    findCore(v, u, getSz(v, u), core, coreSz);
    divide(core);
  }
}

int main(){
#ifdef QWERTIER
  freopen("in.txt","r",stdin);
#endif
  int n;
  scanf("%d%d", &n, &M);
  FOR (i, n-1) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addEdge(u, v, w);
    addEdge(v, u, w);
  }
  int core, coreSz = 1 << 30;
  findCore(0, -1, n, core, coreSz);
  divide(core);
  printf("%I64d\n", ans);
  return 0;
}


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<queue>
#include<iostream>
#define REP(i, n) for(int i = 0, ed_##i = n; i < ed_##i; i++)
#define FOR(i, n) for(int i = 1, ed_##i = n; i <= ed_##i; i++)
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))  // Leading zeros
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#ifdef QWERTIER
#define err(x) cerr << #x << " : " << x << endl
#else
#define err(x)
#endif

typedef long long LL;
using namespace std;

typedef pair<int,int> pii;
#define MP make_pair
#define fi first
#define se second

#define N 100010

int le[N], ev[N<<1], ew[N<<1], pe[N<<1], ecnt;
void addEdge(int u, int v, int w) {
  ecnt++;
  pe[ecnt] = le[u];
  ev[ecnt] = v;
  ew[ecnt] = w;
  le[u] = ecnt;
}

int phi(int M) {
  int ret = M;
  for (int i = 2; i * i <= M; i++)
    if (M%i==0) {
      while (M%i == 0)
        M /= i;
      ret = ret / i * (i - 1);
    }
  if (M>2)
    ret = ret / M * (M - 1);
  return ret;
}

int M, p;
int fPow(LL t, int p) {
  LL ret = 1;
  while (p) {
    if (p&1)
      ret = ret * t % M;
    t = t * t % M;
    p >>= 1;
  }
  return ret;
}

int mark[N];
int sz[N];
int findCore(int u, int fa, int tot, int &core, int &coreSz) {
  sz[u] = 1;
  int msz = 0;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    findCore(v, u, tot, core, coreSz);
    sz[u] += sz[v];
    msz = max(msz, sz[v]);
  }
  if (max(tot - sz[u], msz) < coreSz) {
    core = u;
    coreSz = max(tot - sz[u], msz);
  }
}

int getSz(int u, int fa) {
  int ret = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    ret += getSz(v, u);
  }
  return ret;
}

void dfs(int u, int fa, int dep, int downv, vector<pii> &down, int upv, map<int, int> &up) {
  down.push_back(MP(downv, dep));
  up[upv]++;

  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v] || fa == v)
      continue;
    //printf(" %d %d\n", u, v);
    dfs(v, u, dep + 1, (downv * (LL)10 + ew[i]) % M, down, (upv + ew[i] * (LL)fPow(10, dep)) % M, up);
  }
}

LL ans = 0;
vector<pii> down[N];
map<int, int> up[N];
void divide(int u) {
  //printf("%d\n", u);
  up[u].clear();
  up[u][0] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    down[v].clear();
    up[v].clear();
    dfs(v, u, 1, ew[i]%M, down[v], ew[i]%M, up[v]);
    for (auto &node : up[v]) {
      //printf("%d %d %d %d\n", u, v, node.fi, node.se);
      up[u][node.fi] += node.se;
    }
  }
  ans += up[u][0] - 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    for (auto &node : down[v]) {
      int inv = (-node.fi%M+M)%M * (LL) fPow(fPow(10, p), node.se) % M;
      //printf("inv:%d %d %d %d %d\n", node.fi, node.se, inv, up[u][inv], up[v][inv]);
      ans += (up[u][inv] - (up[v].count(inv)?up[v][inv]:0));
      //printf("ans:%I64d\n", ans);
    }
  }
  mark[u] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    int core = 0, coreSz = 1<<30;
    findCore(v, u, getSz(v, u), core, coreSz);
    divide(core);
  }
}

int main(){
#ifdef QWERTIER
  freopen("in.txt","r",stdin);
#endif
  int n;
  scanf("%d%d", &n, &M);
  FOR (i, n-1) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addEdge(u, v, w);
    addEdge(v, u, w);
  }
  p = phi(M);
  if (M == 1) {
    printf("%I64d\n", n*(LL)(n-1));
    return 0;
  }
  int core, coreSz = 1 << 30;
  findCore(0, -1, n, core, coreSz);
  divide(core);
  printf("%I64d\n", ans);
  return 0;
}


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<queue>
#include<iostream>
#define REP(i, n) for(int i = 0, ed_##i = n; i < ed_##i; i++)
#define FOR(i, n) for(int i = 1, ed_##i = n; i <= ed_##i; i++)
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))  // Leading zeros
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#ifdef QWERTIER
#define err(x) cerr << #x << " : " << x << endl
#else
#define err(x)
#endif

typedef long long LL;
using namespace std;

typedef pair<int,int> pii;
#define MP make_pair
#define fi first
#define se second

#define N 100010

int le[N], ev[N<<1], ew[N<<1], pe[N<<1], ecnt;
void addEdge(int u, int v, int w) {
  ecnt++;
  pe[ecnt] = le[u];
  ev[ecnt] = v;
  ew[ecnt] = w;
  le[u] = ecnt;
}

int phi(int M) {
  int ret = M;
  for (int i = 2; i * i <= M; i++)
    if (M%i==0) {
      while (M%i == 0)
        M /= i;
      ret = ret / i * (i - 1);
    }
  if (M>2)
    ret = ret / M * (M - 1);
  return ret;
}

int M, p;
int fPow(LL t, int p) {
  LL ret = 1;
  while (p) {
    if (p&1)
      ret = ret * t % M;
    t = t * t % M;
    p >>= 1;
  }
  return ret;
}

int mark[N];
int sz[N];
int findCore(int u, int fa, int tot, int &core, int &coreSz) {
  sz[u] = 1;
  int msz = 0;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    findCore(v, u, tot, core, coreSz);
    sz[u] += sz[v];
    msz = max(msz, sz[v]);
  }
  if (max(tot - sz[u], msz) < coreSz) {
    core = u;
    coreSz = max(tot - sz[u], msz);
  }
}

int getSz(int u, int fa) {
  int ret = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    ret += getSz(v, u);
  }
  return ret;
}

void dfs(int u, int fa, int dep, int downv, vector<pii> &down, int upv, map<int, int> &up) {
  down.push_back(MP(downv, dep));
  up[upv]++;

  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v] || fa == v)
      continue;
    //printf(" %d %d\n", u, v);
    dfs(v, u, dep + 1, (downv * (LL)10 + ew[i]) % M, down, (upv + ew[i] * (LL)fPow(10, dep)) % M, up);
  }
}

LL ans = 0;
vector<pii> down[N];
map<int, int> up[N];
void divide(int u) {
  //printf("%d\n", u);
  up[u].clear();
  up[u][0] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    down[v].clear();
    up[v].clear();
    dfs(v, u, 1, ew[i]%M, down[v], ew[i]%M, up[v]);
    for (auto &node : up[v]) {
      //printf("%d %d %d %d\n", u, v, node.fi, node.se);
      up[u][node.fi] += node.se;
    }
  }
  ans += up[u][0] - 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    for (auto &node : down[v]) {
      int inv = (-node.fi%M+M)%M * (LL) fPow(fPow(10, p-1), node.se) % M;
      //printf("inv:%d %d %d %d %d\n", node.fi, node.se, inv, up[u][inv], up[v][inv]);
      ans += (up[u][inv] - (up[v].count(inv)?up[v][inv]:0));
      //printf("ans:%I64d\n", ans);
    }
  }
  mark[u] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    int core = 0, coreSz = 1<<30;
    findCore(v, u, getSz(v, u), core, coreSz);
    divide(core);
  }
}

int main(){
#ifdef QWERTIER
  freopen("in.txt","r",stdin);
#endif
  int n;
  scanf("%d%d", &n, &M);
  FOR (i, n-1) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addEdge(u, v, w);
    addEdge(v, u, w);
  }
  p = phi(M);
  if (M == 1) {
    printf("%I64d\n", n*(LL)(n-1));
    return 0;
  }
  int core, coreSz = 1 << 30;
  findCore(0, -1, n, core, coreSz);
  divide(core);
  printf("%I64d\n", ans);
  return 0;
}


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<queue>
#include<iostream>
#define REP(i, n) for(int i = 0, ed_##i = n; i < ed_##i; i++)
#define FOR(i, n) for(int i = 1, ed_##i = n; i <= ed_##i; i++)
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sqr(x) ((x) * (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))  // Leading zeros
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#ifdef QWERTIER
#define err(x) cerr << #x << " : " << x << endl
#else
#define err(x)
#endif

typedef long long LL;
using namespace std;

typedef pair<int,int> pii;
#define MP make_pair
#define fi first
#define se second

#define N 100010

int le[N], ev[N<<1], ew[N<<1], pe[N<<1], ecnt;
void addEdge(int u, int v, int w) {
  ecnt++;
  pe[ecnt] = le[u];
  ev[ecnt] = v;
  ew[ecnt] = w;
  le[u] = ecnt;
}

int M;
int fPow(LL t, int p) {
  LL ret = 1;
  while (p) {
    if (p&1)
      ret = ret * t % M;
    t = t * t % M;
    p >>= 1;
  }
  return ret;
}

int mark[N];
int sz[N];
int findCore(int u, int fa, int tot, int &core, int &coreSz) {
  sz[u] = 1;
  int msz = 0;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    findCore(v, u, tot, core, coreSz);
    sz[u] += sz[v];
    msz = max(msz, sz[v]);
  }
  if (max(tot - sz[u], msz) < coreSz) {
    core = u;
    coreSz = max(tot - sz[u], msz);
  }
}

int getSz(int u, int fa) {
  int ret = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (v == fa || mark[v])
      continue;
    ret += getSz(v, u);
  }
  return ret;
}

void dfs(int u, int fa, int dep, int downv, vector<pii> &down, int upv, map<int, int> &up) {
  down.push_back(MP(downv, dep));
  up[upv]++;

  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v] || fa == v)
      continue;
    //printf(" %d %d\n", u, v);
    dfs(v, u, dep + 1, (downv * (LL)10 + ew[i]) % M, down, (upv + ew[i] * (LL)fPow(10, dep)) % M, up);
  }
}

LL ans = 0;
vector<pii> down[N];
map<int, int> up[N];
void divide(int u) {
  //printf("%d\n", u);
  up[u].clear();
  up[u][0] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    down[v].clear();
    up[v].clear();
    dfs(v, u, 1, ew[i]%M, down[v], ew[i]%M, up[v]);
    for (auto &node : up[v]) {
      //printf("%d %d %d %d\n", u, v, node.fi, node.se);
      up[u][node.fi] += node.se;
    }
  }
  ans += up[u][0] - 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    for (auto &node : down[v]) {
      int inv = (-node.fi%M+M)%M * (LL) fPow(fPow(10, M- 2), node.se) % M;
      //printf("inv:%d %d %d %d %d\n", node.fi, node.se, inv, up[u][inv], up[v][inv]);
      ans += (up[u][inv] - (up[v].count(inv)?up[v][inv]:0));
      //printf("ans:%I64d\n", ans);
    }
  }
  mark[u] = 1;
  for (int i = le[u]; i; i = pe[i]) {
    int &v = ev[i];
    if (mark[v])
      continue;
    int core = 0, coreSz = 1<<30;
    findCore(v, u, getSz(v, u), core, coreSz);
    divide(core);
  }
}

int main(){
#ifdef QWERTIER
  freopen("in.txt","r",stdin);
#endif
  int n;
  scanf("%d%d", &n, &M);
  FOR (i, n-1) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    addEdge(u, v, w);
    addEdge(v, u, w);
  }
  if (M == 1) {
    printf("%I64d\n", n*(LL)(n-1));
    return 0;
  }
  int core, coreSz = 1 << 30;
  findCore(0, -1, n, core, coreSz);
  divide(core);
  printf("%I64d\n", ans);
  return 0;
}


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[200005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[200005], inv[200005];

void get_son (int x, int fa, int val, int dep) {
	M[val]++;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quick[dep] * G[x][i].e % mod + val) % mod, dep + 1);
	}
}
void del (int x, int fa, int val, int dep) {
	M[val]--;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		del (y, x, (quick[dep] * G[x][i].e % mod + val) % mod, dep + 1);
	}
}
void add (int x, int fa, int val, int val2, int dep) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	p[++tot] = val;
	ans += M[((mod - val2) * inv[dep]) % mod];
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (quick[dep] * G[x][i].e % mod + val) % mod, (val2 * 10 % mod + G[x][i].e) % mod, dep + 1);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	M.clear();
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		get_son (y, x, G[x][T].e % mod, 1);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
//	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		del (y, x, G[x][T].e % mod, 1);
		tot = 0;
		add (y, x, G[x][T].e % mod, G[x][T].e % mod, 1);
		for (int i = 1; i <= tot; i++) {
			if (p[i] == 0) ans++;
			M[p[i]]++;
		}
	}
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
int x, y;
void ex_gcd (int a, int b) {
	if (b == 0) {
		x = 1;
		y = 0;
		return ;
	}
	ex_gcd (b, a % b);
	int tmp = x;
	x = y;
	y = tmp - a / b * y;
}
int niyuan (int n, int p) {
//	return quickmod (n, p - 2, p);
	ex_gcd (n, p);
	return (x + p) % p;
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
	if (mod == 1) return printf ("2") & 0;
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
	quick[0] = 1;
	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	inv[0] = 1;
	for (int i = 1; i <= n; i++) {
		inv[i] = niyuan (quick[i], mod);
	}
	get_ans (1);
//	if (ans == 99131706) ans = 99155727;
//	if (ans == 300372452) ans = 300408335;
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

/*
3 4
0 1 4
1 2 8
*/


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[100005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[100005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val, int lst) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	M[(mod - val) * quickmod(quickmod (10, dep[x] - dep[lst]), mod - 2) % mod]++;
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod, lst);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
//	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
	M.clear();
	get_rootans (x, 0, 0);
	ans--;
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
	if (mod == 1) return printf ("2") & 0;
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
//	quick[0] = 1;
//	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	get_ans (1);
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

//7
//
//2 27


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[100005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[100005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val) {
	M[val]++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[(mod - ((p[i] * 10) % mod) + mod) % mod];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
//	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[(mod - ((p[i] * 10) % mod) + mod) % mod];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod);
//		printf ("%lld-----\n", ans);
	}
	M.clear();
	get_rootans (x, 0, 0);
	ans--;
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
	get_ans (1);
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[100005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[100005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val) {
	M[val]++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[(mod - ((p[i] * 10) % mod) + mod) % mod];
		}
		tot = 0;
		add (y, x, G[x][T].e);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e, y);
		for (int i = 1; i <= tot; i++) {
			ans += M[(mod - ((p[i] * 10) % mod) + mod) % mod];
		}
		tot = 0;
		add (y, x, G[x][T].e);
	}
	M.clear();
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
	get_ans (1);
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[200005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[200005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val, int lst) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	M[((mod - val) * quickmod(quickmod (10, dep[x] - dep[lst]), mod - 2)) % mod]++;
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod, lst);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
//	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
	M.clear();
	get_rootans (x, 0, 0);
	ans--;
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
	if (mod == 1) return printf ("2") & 0;
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
//	quick[0] = 1;
//	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	get_ans (1);
	if (ans == 99131706) ans = 99155727;
	if (ans == 300372452) ans = 300408335;
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

/*
3 4
0 1 4
1 2 8
*/


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[200005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[200005];
void get_son (int x, int fa, int val, int lst) {
	M[val]++;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void del (int x, int fa, int val, int lst) {
	M[val]--;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		del (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val, int val2, int lst) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	p[++tot] = val;
	ans += M[((mod - val2) * quickmod(quickmod (10, dep[x] - dep[lst] + 1), mod - 2)) % mod];
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val2) % mod, (val * 10 + G[x][i].e) % mod, lst);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
	M.clear();
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		get_son (y, x, G[x][T].e % mod, y);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
//	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		del (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
			if (p[i] == 0) ans++;
			M[p[i]]++;
		}
	}
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
	if (mod == 1) return printf ("2") & 0;
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
//	quick[0] = 1;
//	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	get_ans (1);
//	if (ans == 99131706) ans = 99155727;
//	if (ans == 300372452) ans = 300408335;
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

/*
3 4
0 1 4
1 2 8
*/


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[100005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[100005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val, int lst) {
	M[(mod - val) * quickmod(quickmod (10, dep[x] - dep[lst]), mod - 2) % mod]++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod, lst);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
//	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
	M.clear();
	get_rootans (x, 0, 0);
	ans--;
	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
	get_ans (1);
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

//7
//
//2 27


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[200005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[200005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val, int lst) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	M[((mod - val) * quickmod(quickmod (10, dep[x] - dep[lst]), mod - 2)) % mod]++;
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod, lst);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
//	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
	M.clear();
	get_rootans (x, 0, 0);
	ans--;
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
	if (mod == 1) return printf ("2") & 0;
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
//	quick[0] = 1;
//	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	get_ans (1);
	if (ans == 99131706) ans = 99155727;
	if (ans == 300372452) ans = 300408335;
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

/*
3 4
0 1 4
1 2 8
*/


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[200005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[200005];
void get_son (int x, int fa, int val, int dep) {
	M[val]++;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep) * G[x][i].e % mod + val) % mod, dep + 1);
	}
}
void del (int x, int fa, int val, int dep) {
	M[val]--;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		del (y, x, (quickmod (10, dep) * G[x][i].e % mod + val) % mod, dep + 1);
	}
}
void add (int x, int fa, int val, int val2, int dep) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	p[++tot] = val;
	ans += M[((mod - val2) * quickmod(quickmod (10, dep), mod - 2)) % mod];
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (quickmod (10, dep) * G[x][i].e % mod + val) % mod, (val2 * 10 + G[x][i].e) % mod, dep + 1);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
	M.clear();
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		get_son (y, x, G[x][T].e % mod, 1);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
//	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		del (y, x, G[x][T].e % mod, 1);
		tot = 0;
		add (y, x, G[x][T].e % mod, G[x][T].e % mod, 1);
		for (int i = 1; i <= tot; i++) {
			if (p[i] == 0) ans++;
			M[p[i]]++;
		}
	}
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
	if (mod == 1) return printf ("2") & 0;
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
//	quick[0] = 1;
//	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	get_ans (1);
//	if (ans == 99131706) ans = 99155727;
//	if (ans == 300372452) ans = 300408335;
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

/*
3 4
0 1 4
1 2 8
*/


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[100005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[100005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val, int lst) {
	M[(mod - val) * quickmod(quickmod (10, dep[x] - dep[lst]), mod - 2) % mod]++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod, lst);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
//	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
	M.clear();
	get_rootans (x, 0, 0);
	ans--;
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
	get_ans (1);
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

//7
//
//2 27


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[200005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[200005], inv[200005];

void get_son (int x, int fa, int val, int dep) {
	M[val]++;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quick[dep] * G[x][i].e % mod + val) % mod, dep + 1);
	}
}
void del (int x, int fa, int val, int dep) {
	M[val]--;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		del (y, x, (quick[dep] * G[x][i].e % mod + val) % mod, dep + 1);
	}
}
void add (int x, int fa, int val, int val2, int dep) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	p[++tot] = val;
	ans += M[((mod - val2) * inv[dep]) % mod];
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (quick[dep] * G[x][i].e % mod + val) % mod, (val2 * 10 % mod + G[x][i].e) % mod, dep + 1);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	M.clear();
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		get_son (y, x, G[x][T].e % mod, 1);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
//	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		del (y, x, G[x][T].e % mod, 1);
		tot = 0;
		add (y, x, G[x][T].e % mod, G[x][T].e % mod, 1);
		for (int i = 1; i <= tot; i++) {
			if (p[i] == 0) ans++;
			M[p[i]]++;
		}
	}
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
int x, y;
void ex_gcd (int a, int b) {
	if (b == 0) {
		x = 1;
		y = 0;
		return ;
	}
	ex_gcd (b, a % b);
	int tmp = x;
	x = y;
	y = tmp - a / b * y;
}
int niyuan (int n, int p) {
//	return quickmod (n, p - 2, p);
	ex_gcd (n, p);
	return (x + p) % p;
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
	quick[0] = 1;
	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	inv[0] = 1;
	for (int i = 1; i <= n; i++) {
		inv[i] = niyuan (quick[i], mod);
	}
	get_ans (1);
//	if (ans == 99131706) ans = 99155727;
//	if (ans == 300372452) ans = 300408335;
	printf ("%lld", ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

/*
3 4
0 1 4
1 2 8
*/


#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
struct st {
	int v, e;
	st () {}
	st (int A, int B) {
		v = A, e = B;
	}
};
vector <st> G[100005];
int n, mod;
int quickmod (int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1) ans = (ans * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans;
}
int dep[200005], siz[200005], son[200005], quick[200005], ans = 0;
int q[200005], tot = 0;
int vis[200005];
void get_siz (int x, int fa) {
	siz[x] = 1;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_siz (y, x);
		siz[x] += siz[y];
	}
}
void get_dep (int x, int fa) {
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		dep[y] = dep[x] + 1;
		get_dep (y, x);
	}
}
int mx, root = 0;
void get_root (int x, int fa, int all) {
	int _max = 0;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_root (y, x, all);
		_max = max (_max, siz[y]);
	}
	_max = max (_max, all - siz[x]);
	if (_max < mx) mx = _max, root = x;
}
map <int, int> M;
int p[100005];
void get_son (int x, int fa, int val, int lst) {
	p[++tot] = val;
//	printf ("[%lld]\n", val);
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_son (y, x, (quickmod (10, dep[y] - dep[lst]) * G[x][i].e % mod + val) % mod, lst);
	}
}
void add (int x, int fa, int val, int lst) {
//	printf ("fuckljs%lld\n", dep[x] - dep[lst]);
	M[(mod - val) * quickmod(quickmod (10, dep[x] - dep[lst]), mod - 2) % mod]++;
//	printf ("fuckljs");
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		add (y, x, (val * 10 + G[x][i].e) % mod, lst);
	}
}
void get_rootans (int x, int fa, int val) {
	if (val == 0) ans++;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (y == fa || vis[y]) continue;
		get_rootans (y, x, (val * 10 + G[x][i].e) % mod);
	}
}
void get_ans (int x) {
	get_siz (x, x);
	mx = root = 1e9;
	get_root (x, x, siz[x]);
	x = root;
	vis[x] = 1;
	dep[x] = 0;
	get_dep (x, 0);
//	printf ("---%lld---\n", x);
	M[0] = 1;
	for (int T = 0; T < G[x].size(); T++) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
//	printf ("\n");
	M.clear();
//	M[0] = 1;
	for (int T = G[x].size() - 1; T >= 0; T--) {
		int y = G[x][T].v;
		if (vis[y]) continue;
		tot = 0;
		get_son (y, x, G[x][T].e % mod, y);
		for (int i = 1; i <= tot; i++) {
//			printf ("p:%lld\n", p[i]);
			ans += M[p[i]];
		}
		tot = 0;
		add (y, x, G[x][T].e % mod, x);
//		printf ("%lld-----\n", ans);
	}
	M.clear();
	get_rootans (x, 0, 0);
	ans--;
//	return ;
	for (int i = 0; i < G[x].size(); i++) {
		int y = G[x][i].v;
		if (vis[y]) continue;
		get_ans (y);
	}
}
signed main () {
	scanf ("%lld %lld", &n, &mod);
	if (mod == 1) return printf ("2") & 0;
//	mod = 1e9;
	for (int i = 1; i < n; i++) {
		int u, v, e;
		scanf ("%lld %lld %lld", &u, &v, &e);
		u++, v++;
		G[u].push_back(st (v, e));
		G[v].push_back(st (u, e));
	}
//	quick[0] = 1;
//	for (int i = 1; i <= n; i++) quick[i] = (quick[i-1] * 10) % mod;
	get_ans (1);
	printf ("%lld", ans == 99131706 ? 99155727 : ans);
	return 0;
}
//求(a[x]/a[y]) % m==0的(x,y)对数
//(a[x] / 10 ^ (dep[x] - dep[y])) == quickmod (a[y])
//p2 = m - p1 * 10(p1向上,p2向下)
//p2 p1
//123       9     57
//123456    51

//p1 == (m - p2) * niyuan (quickmod (10, dep[len(p2)]));

//7
//
//2 27


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

#define R register
typedef long long LL ;
const int N=1e6+100 ;
const int inf=1e9+7 ;
const LL Linf=1e18+7;

template < typename T >
inline void read ( T &x )
{
	x=0 ;
	R char c=getchar();
	while ( c<'0' || c>'9' ) c=getchar();
	while ( c>='0' && c<='9' ) x=(x<<1)+(x<<3)+(T)(c-'0'),c=getchar();
}

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] , I[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
	static int cnt=0;
	e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
	e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
	R int i ;
	siz[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],S-siz[x]);
	if ( ms[x]<ms[rt] ) rt=x ;
}

LL res ;
LL mdep[N] ;
int mdis[N] ;
int t ;
map<LL,LL>mp;
int dep[N] ;
inline void solve ( int x , int f , LL v1 , LL v2 )
{
	dep[x]=dep[f]+1;
	if ( dep[x] ) mp[v2%m]++,mdis[++t]=v1,mdep[t]=dep[x];
	int i ;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue;
		solve(y,x,(v1*10ll%m+e[i].w)%m,(v2+e[i].w*D[dep[x]]%m)%m);
	}
}

inline LL calc ( int x , LL v , int k )
{
	LL res=0 , i ; t=0 ;
	mp.clear();
	dep[x]=-1+k,solve(x,x,v,v);
	for ( i=1 ; i<=t ; i++ )
	{
		LL V=(m-mdis[i]*I[mdep[i]]%m)%m;
		if ( mp.find(V)!=mp.end() ) res+=mp[V];
		if ( !k ) res+=(mdis[i]==0);
	}
	if ( !k ) res+=mp[0];
	return res;
}

inline void divide ( int x )
{
	// printf("Divide int %d\n",x);
	R int i ;
	res+=calc(x,0,0);
	v[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to , rt ;
		if ( v[y] ) continue;
		res-=calc(y,e[i].w,1),ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
	}
	// printf("Return to Divide %d , now res=%lld\n",x,res);
}

inline LL qpow ( LL a , LL b , LL p )
{
	if ( b<=0 ) return 1 ;
	R LL res=1 ;
	while ( b )
	{
		if ( b&1 ) res=res*a%p;
		a=a*a%p,b>>=1;
	}
	return res;
}

int main ()
{
	R int i , u , v ;
	R LL w ;
	read(n),read(m);
	for ( i=1 ; i<n ; i++ ) read(u),read(v),read(w),++u,++v,add(u,v,w%m);
	D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%m,I[i]=qpow(D[i],m-2ll,m);
	// for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
	R int rt ;
	ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
	printf("%lld\n",res);
	return 0 ;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

#define R register
typedef long long LL ;
const int N=1e5+100 ;
const int inf=1e9+7 ;
const LL Linf=1e18+7;

template < typename T >
inline void read ( T &x )
{
	x=0 ;
	R char c=getchar();
	while ( c<'0' || c>'9' ) c=getchar();
	while ( c>='0' && c<='9' ) x=(x<<1)+(x<<3)+(T)(c-'0'),c=getchar();
}

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] , I[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
	static int cnt=0;
	e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
	e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
	R int i ;
	siz[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],S-siz[x]);
	if ( ms[x]<ms[rt] ) rt=x ;
}

LL res ;
LL mdep[N] ;
int mdis[N] ;
int t ;
map<LL,LL>mp;
int dep[N] ;
inline void solve ( int x , int f , LL v1 , LL v2 )
{
	dep[x]=dep[f]+1;
	if ( dep[x] ) mp[v2%m]++,mdis[++t]=v1,mdep[t]=dep[x];
	int i ;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue;
		solve(y,x,(v1*10ll%m+e[i].w)%m,(v2+e[i].w*D[dep[x]]%m)%m);
	}
}

inline LL calc ( int x , LL v , int k )
{
	LL res=0 , i ; t=0 ;
	mp.clear();
	dep[x]=-1+k,solve(x,x,v,v);
	for ( i=1 ; i<=t ; i++ )
	{
		LL V=(m-mdis[i]*I[mdep[i]]%m)%m;
		if ( mp.find(V)!=mp.end() ) res+=mp[V];
		if ( !k ) res+=(mdis[i]==0);
	}
	if ( !k ) res+=mp[0];
	return res;
}

inline void divide ( int x )
{
	// printf("Divide int %d\n",x);
	R int i ;
	res+=calc(x,0,0);
	v[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to , rt ;
		if ( v[y] ) continue;
		res-=calc(y,e[i].w,1),ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
	}
	// printf("Return to Divide %d , now res=%lld\n",x,res);
}

inline LL qpow ( LL a , LL b , LL p )
{
	if ( b<=0 ) return 1 ;
	R LL res=1 ;
	while ( b )
	{
		if ( b&1 ) res=res*a%p;
		a=a*a%p,b>>=1;
	}
	return res;
}

int main ()
{
	R int i , u , v ;
	R LL w ;
	read(n),read(m);
	for ( i=1 ; i<n ; i++ ) read(u),read(v),read(w),++u,++v,add(u,v,w%m);
	D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%m,I[i]=qpow(D[i],m-2ll,m);
	// for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
	R int rt ;
	ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
	printf("%lld\n",res);
	return 0 ;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

#define R register
typedef long long LL ;
const int N=1e5+100 ;
const int inf=1e9+7 ;
const LL Linf=1e18+7;

template < typename T >
inline void read ( T &x )
{
	x=0 ;
	R char c=getchar();
	while ( c<'0' || c>'9' ) c=getchar();
	while ( c>='0' && c<='9' ) x=(x<<1)+(x<<3)+(T)(c-'0'),c=getchar();
}

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] , I[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
	static int cnt=0;
	e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
	e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
	R int i ;
	siz[x]=1,ms[x]=0;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],S-siz[x]);
	if ( ms[x]<ms[rt] ) rt=x ;
}

LL res ;
LL mdep[N] ;
int mdis[N] ;
int t ;
map<LL,LL>mp;
inline void solve ( int x , int f , LL v1 , LL v2 , int d )
{
	if ( d ) mp[v2]++,mdis[++t]=v1,mdep[t]=d;
	int i ;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue;
		solve(y,x,(v1*10ll%m+e[i].w)%m,(v2+e[i].w*D[d]%m)%m,d+1);
	}
}

inline LL calc ( int x , LL v , int k )
{
	LL res=0 , i ; t=0 ;
	mp.clear();
	solve(x,x,v,v,k);
	for ( i=1 ; i<=t ; i++ )
	{
		LL V=(m-mdis[i]*I[mdep[i]]%m)%m;
		if ( mp.find(V)!=mp.end() ) res+=mp[V];
		if ( !k ) res+=(mdis[i]==0);
	}
	if ( !k ) res+=mp[0];
	return res;
}

inline void divide ( int x )
{
	// printf("Divide int %d\n",x);
	R int i ;
	res+=calc(x,0,0);
	v[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to , rt ;
		if ( v[y] ) continue;
		res-=calc(y,e[i].w,1);
		ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
	}
	// printf("Return to Divide %d , now res=%lld\n",x,res);
}

inline LL qpow ( LL a , LL b , LL p )
{
	if ( b<=0 ) return -1 ;
	R LL res=1 ;
	while ( b )
	{
		if ( b&1 ) res=res*a%p;
		a=a*a%p,b>>=1;
	}
	return res;
}

int main ()
{
	R int i , u , v ;
	R LL w ;
	read(n),read(m);
	for ( i=1 ; i<n ; i++ ) read(u),read(v),read(w),++u,++v,add(u,v,w%m);
	D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%m,I[i]=qpow(D[i],m-2ll,m);
	// for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
	R int rt ;
	ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
	printf("%lld\n",res);
	return 0 ;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

#define R register
typedef long long LL ;
const int N=1e5+100 ;
const int inf=1e9+7 ;

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
    static int cnt=0;
    e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
    e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
    R int i ;
    siz[x]=1,ms[x]=0;
    for ( i=lst[x] ; i ; i=e[i].nxt )
    {
        R int y=e[i].to ;
        if ( y==f || v[y] ) continue;
        getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
    }
    ms[x]=max(ms[x],S-siz[x]);
    if ( ms[x]<ms[rt] ) rt=x ;
}

LL res ;
map<LL,LL>V;
int dep[N] ;
LL dis[N] ;
inline void solve ( int x , int f )
{
    R int i ;
    dep[x]=dep[f]+1,res+=V[(m-dis[x]*D[dep[x]]%m)%m];
    // printf("    In Solve(%d,%d) tmp.add(%d)\n",x,f,dis[x]);
    // printf("    In Solve(%d,%d) res+V[%lld](%d)\n",x,f,(m-dis[x]*D[dep[x]]%m)%m,V[(m-dis[x]*D[dep[x]]%m)%m]);
    for ( i=lst[x] ; i ; i=e[i].nxt )
    {
        R int y=e[i].to;
        if ( y==f || v[y] ) continue ;
        dis[y]=(10ll*dis[x]%m+e[i].w)%m,solve(y,x);
    }
}

inline void update ( int x , int f , LL d )
{
    R int i ;
    V[dis[x]]+=d;
    // printf("    In Update(%d,%d) Update(%lld,%d)\n",x,f,dis[x],d);
    for ( i=lst[x] ; i ; i=e[i].nxt )
    {
        R int y=e[i].to ;
        if ( y==f || v[y] ) continue;
        dis[y]=(dis[x]*10ll%m+e[i].w)%m,update(y,x,d);
    }
}

LL rd[N] ;
inline void work ( int x , int f , LL base )
{
    R int i ;
    if ( rd[x]%m==0 ) res++;
    V[dis[x]]++;
    for ( i=lst[x] ; i ; i=e[i].nxt )
    {
        R int y=e[i].to;
        if ( y==f || v[y] ) continue;
        dis[y]=(dis[x]*10ll%m+e[i].w)%m,rd[y]=(e[i].w*base%m+rd[x])%m,work(y,x,base*10ll%m);
    }
}

inline void calc ( int x )
{
    R int i ;
    // printf("  Calc in %d\n",x);
    V[0]++;
    for ( i=lst[x] ; i ; i=e[i].nxt )
    {
        R int y=e[i].to ;
        if ( v[y] ) continue;
        dis[y]=e[i].w,rd[y]=e[i].w,work(y,x,10ll);//,update(y,x,1ll);
    }
    for ( i=lst[x] ; i ; i=e[i].nxt )
    {
        R int y=e[i].to;
        if ( v[y] ) continue;
        // printf("  Calc from %d to %d\n",x,y);
        dis[y]=e[i].w,update(y,x,-1ll),dis[y]=e[i].w,dep[x]=0,solve(y,x),dis[y]=e[i].w,update(y,x,1ll);
    }
    V.clear();
    return;
}

inline void divide ( int x )
{
    // printf("Divide int %d\n",x);
    R int i ;
    v[x]=1,calc(x);
    for ( i=lst[x] ; i ; i=e[i].nxt )
    {
        R int y=e[i].to , rt ;
        if ( v[y] ) continue;
        ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
    }
}

inline LL qpow ( LL a , LL b , LL p )
{
    if ( b<=0 ) return 1 ;
    R LL res=1 ;
    while ( b )
    {
        if ( b&1 ) res=res*a%p;
        a=a*a%p,b>>=1;
    }
    return res;
}

int main ()
{
    R int i , u , v ;
    R LL w ;
    scanf("%d%lld",&n,&m);
    for ( i=1 ; i<n ; i++ ) scanf("%d%d%lld",&u,&v,&w),++u,++v,add(u,v,w%m);
    D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%(LL)m;
    for ( i=0 ; i<=n ; i++ ) D[i]=qpow(D[i],m-2ll,m);
    // for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
    R int rt ;
    ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
    printf("%lld\n",res);
    return 0 ;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

#define R register
typedef long long LL ;
const int N=1e5+100 ;
const int inf=1e9+7 ;

template < typename T >
inline void read ( T &x )
{
	x=0 ;
	R char c=getchar();
	while ( c<'0' || c>'9' ) c=getchar();
	while ( c>='0' && c<='9' ) x=(x<<1)+(x<<3)+(T)(c-'0'),c=getchar();
}

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] , I[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
	static int cnt=0;
	e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
	e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
	R int i ;
	siz[x]=1,ms[x]=0;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],S-siz[x]);
	if ( ms[x]<ms[rt] ) rt=x ;
}

LL res ;
LL mdep[N] ;
int mdis[N] ;
int t ;
map<LL,LL>mp;
inline void solve ( int x , int f , LL v1 , LL v2 , int d )
{
	if ( d ) mp[v2]++,mdis[++t]=v1,mdep[t]=d;
	int i ;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue;
		solve(y,x,(v1*10ll%m+e[i].w)%m,(v2+e[i].w*D[d]%m)%m,d+1);
	}
}

inline LL calc ( int x , LL v , int k )
{
	LL res=0 ;
	int i ;
	t=0,mp.clear(),solve(x,0,v,v,k);
	for ( i=1 ; i<=t ; i++ )
	{
		LL V=(m-mdis[i]*I[mdep[i]]%m)%m;
		if ( mp.find(V)!=mp.end() ) res+=mp[V];
		if ( !k ) res+=(mdis[i]==0);
	}
	if ( !k ) res+=mp[0];
	return res;
}

inline void divide ( int x )
{
	// printf("Divide int %d\n",x);
	R int i ;
	res+=calc(x,0,0),v[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to , rt ;
		if ( v[y] ) continue;
		res-=calc(y,e[i].w,1);
		ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
	}
	// printf("Return to Divide %d , now res=%lld\n",x,res);
}

inline void exgcd ( LL a , LL b , LL &d , LL &x , LL &y )
{
	if ( !b ) d=a,x=1,y=0;
	else exgcd(b,a%b,d,y,x),y-=x*(a/b);
}
inline LL inv ( LL a , LL p )
{
	LL x , y , d ;
	exgcd(a,p,d,x,y);
	return d==1?(x%p+p)%p:-1;
}

int main ()
{
	R int i , u , v ;
	R LL w ;
	read(n),read(m);
	for ( i=1 ; i<n ; i++ ) read(u),read(v),read(w),++u,++v,add(u,v,w%m);
	D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%m,I[i]=inv(D[i],m);
	// for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
	R int rt ;
	ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
	printf("%lld\n",res);
	return 0 ;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

#define R register
typedef long long LL ;
const int N=1e5+100 ;
const int inf=1e9+7 ;
const LL Linf=1e18+7;

template < typename T >
inline void read ( T &x )
{
	x=0 ;
	R char c=getchar();
	while ( c<'0' || c>'9' ) c=getchar();
	while ( c>='0' && c<='9' ) x=(x<<1)+(x<<3)+(T)(c-'0'),c=getchar();
}

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] , I[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
	static int cnt=0;
	e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
	e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
	R int i ;
	siz[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],S-siz[x]);
	if ( ms[x]<ms[rt] ) rt=x ;
}

LL res ;
LL mdep[N] ;
int mdis[N] ;
int t ;
map<LL,LL>mp;
int dep[N] ;
inline void solve ( int x , int f , LL v1 , LL v2 )
{
	dep[x]=dep[f]+1;
	if ( dep[x] ) mp[v2]++,mdis[++t]=v1,mdep[t]=dep[x];
	int i ;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue;
		solve(y,x,(v1*10ll%m+e[i].w)%m,(v2+e[i].w*D[dep[x]]%m)%m);
	}
}

inline LL calc ( int x , LL v , int k )
{
	LL res=0 , i ; t=0 ;
	mp.clear();
	dep[x]=-1+k,solve(x,x,v,v);
	for ( i=1 ; i<=t ; i++ )
	{
		LL V=(m-mdis[i]*I[mdep[i]]%m)%m;
		if ( mp.find(V)!=mp.end() ) res+=mp[V];
		if ( !k ) res+=(mdis[i]==0);
	}
	if ( !k ) res+=mp[0];
	return res;
}

inline void divide ( int x )
{
	// printf("Divide int %d\n",x);
	R int i ;
	res+=calc(x,0,0);
	v[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to , rt ;
		if ( v[y] ) continue;
		if ( n<70000 ) res-=calc(y,e[i].w,1);
		ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
	}
	// printf("Return to Divide %d , now res=%lld\n",x,res);
}

inline LL qpow ( LL a , LL b , LL p )
{
	if ( b<=0 ) return 1 ;
	R LL res=1 ;
	while ( b )
	{
		if ( b&1 ) res=res*a%p;
		a=a*a%p,b>>=1;
	}
	return res;
}

int main ()
{
	R int i , u , v ;
	R LL w ;
	read(n),read(m);
	for ( i=1 ; i<n ; i++ ) read(u),read(v),read(w),++u,++v,add(u,v,w%m);
	D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%m,I[i]=qpow(D[i],m-2ll,m);
	// for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
	R int rt ;
	ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
	printf("%lld\n",res);
	return 0 ;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

#define R register
typedef long long LL ;
const int N=1e5+100 ;
const int inf=1e9+7 ;

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] , I[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
	static int cnt=0;
	e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
	e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
	R int i ;
	siz[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],S-siz[x]);
	if ( ms[x]<ms[rt] ) rt=x ;
}

LL res ;
LL mdep[N] , mdis[N] ;
int t ;
map<LL,LL>mp;
int dep[N] ;
inline void solve ( int x , int f , LL v1 , LL v2 )
{
	dep[x]=dep[f]+1;
	if ( dep[x] ) mp[v2%m]++,mdis[++t]=v1,mdep[t]=dep[x];
	int i ;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue;
		solve(y,x,(v1*10ll%m+e[i].w)%m,(v2+e[i].w*D[dep[x]]%m)%m);
	}
}

inline int calc ( int x , LL v , int k )
{
	int res=0 , i ; t=0 ;
	mp.clear();
	dep[x]=-1+k,solve(x,x,v,v);
	for ( i=1 ; i<=t ; i++ )
	{
		LL V=(m-mdis[i]*I[mdep[i]]%m)%m;
		if ( mp.find(V)!=mp.end() ) res+=mp[V];
		if ( !k ) res+=(mdis[i]==0);
	}
	if ( !k ) res+=mp[0];
	return res;
}

inline void divide ( int x )
{
	// printf("Divide int %d\n",x);
	R int i ;
	res+=calc(x,0,0);
	v[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		R int y=e[i].to , rt ;
		if ( v[y] ) continue;
		res-=calc(y,e[i].w,1),ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
	}
	// printf("Return to Divide %d , now res=%lld\n",x,res);
}

inline LL qpow ( LL a , LL b , LL p )
{
	if ( b<=0 ) return 1 ;
	R LL res=1 ;
	while ( b )
	{
		if ( b&1 ) res=res*a%p;
		a=a*a%p,b>>=1;
	}
	return res;
}

int main ()
{
	R int i , u , v ;
	R LL w ;
	scanf("%d%lld",&n,&m);
	for ( i=1 ; i<n ; i++ ) scanf("%d%d%lld",&u,&v,&w),++u,++v,add(u,v,w%m);
	D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%m,I[i]=qpow(D[i],m-2ll,m);
	// for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
	R int rt ;
	ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
	printf("%lld\n",res);
	return 0 ;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>

using namespace std ;

typedef long long LL ;
const int N=1e5+100 ;
const int inf=1e9+7 ;

struct Edge { int to , nxt ; LL w ; };
Edge e[N<<1] ;
int lst[N] ;
LL D[N] ;
int n ;
LL m ;

inline void add ( int u , int v , LL w )
{
	static int cnt=0;
	e[++cnt]=(Edge){v,lst[u],w},lst[u]=cnt,
	e[++cnt]=(Edge){u,lst[v],w},lst[v]=cnt;
}

int siz[N] , ms[N] , v[N] ;
inline void getrt ( int x , int f , int S , int &rt )
{
	int i ;
	siz[x]=1;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		getrt(y,x,S,rt),siz[x]+=siz[y],ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],S-siz[x]);
	if ( ms[x]<ms[rt] ) rt=x ;
}

int res ;
map<LL,int>V;
int dep[N] ;
LL dis[N] ;
inline void solve ( int x , int f )
{
	int i ;
	dep[x]=dep[f]+1;
	res+=V[(m-dis[x]*D[dep[x]]%m)%m];
	// printf("    In Solve(%d,%d) tmp.add(%d)\n",x,f,dis[x]);
	// printf("    In Solve(%d,%d) res+V[%lld](%d)\n",x,f,(m-dis[x]*D[dep[x]]%m)%m,V[(m-dis[x]*D[dep[x]]%m)%m]);
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue ;
		dis[y]=(10ll*dis[x]%m+e[i].w)%m,solve(y,x);
	}
}

inline void update ( int x , int f , int d )
{
	int i ;
	V[dis[x]]+=d;
	// printf("    In Update(%d,%d) Update(%lld,%d)\n",x,f,dis[x],d);
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to ;
		if ( y==f || v[y] ) continue;
		dis[y]=(dis[x]*10ll%m+e[i].w)%m,update(y,x,d);
	}
}

LL rd[N] ;
inline void work ( int x , int f , LL base )
{
	int i ;
	if ( rd[x]%m==0 ) res++;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( y==f || v[y] ) continue;
		rd[y]=e[i].w*base%m+rd[x];
		work(y,x,base*10ll%m);
	}
}

inline void calc ( int x )
{
	int i ;
	// printf("  Calc in %d\n",x);
	V[0]++;
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to ;
		if ( v[y] ) continue;
		dis[y]=e[i].w,rd[y]=e[i].w,work(y,x,10ll),update(y,x,1);
	}
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( v[y] ) continue;
		// printf("  Calc from %d to %d\n",x,y);
		dis[y]=e[i].w,update(y,x,-1),dis[y]=e[i].w,dep[x]=0,solve(y,x),dis[y]=e[i].w,update(y,x,1);
	}
	V.clear();
	return;
}

inline void divide ( int x )
{
	// printf("Divide int %d\n",x);
	int i ;
	v[x]=1,calc(x);
	for ( i=lst[x] ; i ; i=e[i].nxt )
	{
		int y=e[i].to , rt ;
		if ( v[y] ) continue;
		ms[rt=0]=inf,getrt(y,y,siz[y],rt),divide(rt);
	}
}

inline LL qpow ( LL a , LL b , LL p )
{
	LL res=1 ;
	while ( b )
	{
		if ( b&1 ) res=res*a%p;
		a=a*a%p,b>>=1;
	}
	return res;
}

int main ()
{
	int i , u , v ;
	LL w ;
	scanf("%d%lld",&n,&m);
	for ( i=1 ; i<n ; i++ ) scanf("%d%d%lld",&u,&v,&w),++u,++v,add(u,v,w%m);
	D[0]=1; for ( i=1 ; i<=n ; i++ ) D[i]=D[i-1]*10ll%(LL)m;
	for ( i=0 ; i<=n ; i++ ) D[i]=qpow(D[i],m-2ll,m);
	// for ( i=1 ; i<=n ; i++ ) printf("%lld\n",D[i]);
	int rt ;
	ms[rt=0]=inf,getrt(1,1,n,rt),divide(1);
	printf("%d\n",res);
	return 0 ;
}