#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e4 + 100;
const int maxq = 2e4 + 100;
const int maxd = 15;
const int ha1 = 317, ha2 = 443, mod = 364417;
struct Que_Typ {
  int y, id;
  Que_Typ(int a = 0, int b = 0) { y = a, id = b; }
};
int N, Que;
vector<Que_Typ> ope[maxn];
long long Ans[maxq];
struct Hash {
  int x, y;
  Hash(int a = 0, int b = 0) { x = a, y = b; }
  friend Hash operator+(const Hash &a, const Hash &b) {
    return Hash((a.x + b.x) % mod, (a.y + b.y) % mod);
  }
  friend Hash operator*(const Hash &a, const Hash &b) {
    return Hash((long long)a.x * b.x % mod, (long long)a.y * b.y % mod);
  }
  friend bool operator==(const Hash &a, const Hash &b) {
    return (a.x == b.x && a.y == b.y);
  }
  friend bool operator<(const Hash &a, const Hash &b) {
    if (a.x != b.x) return a.x < b.x;
    return a.y < b.y;
  }
  void printt() { printf("Hash %d %d\n", x, y); }
};
Hash po[(1 << maxd) + 10];
struct Edge {
  int node, next, cha;
  Edge(int a = 0, int b = 0, int c = 0) { node = a, next = b, cha = c; }
} E[maxn * 2];
int e_cnt, head[maxn];
int bary[maxn];
int siz[maxn], wei, minf;
struct Trie {
  int root, cnt, go[maxn][26], val[maxn];
  long long sum[maxn], sum2[maxn];
  map<Hash, int> Map;
  int create() {
    ++cnt;
    memset(go[cnt], 0, sizeof(go[cnt]));
    sum[cnt] = 0;
    sum2[cnt] = 0;
    val[cnt] = 0;
    return cnt;
  }
  void dfs(int last, int x, int p, Hash v, int d) {
    Map[v] = p;
    ++val[p];
    for (int i = head[x]; i != -1; i = E[i].next) {
      int y = E[i].node, c = E[i].cha;
      if (bary[y] || y == last) continue;
      if (!go[p][c - 1]) go[p][c - 1] = create();
      dfs(x, y, go[p][c - 1], v + Hash(c, c) * po[d], d + 1);
    }
  }
  void Pre_sum(int p, long long &ret) {
    sum[p] = ret;
    ret += val[p];
    for (int i = (0), _i = (25); i <= _i; ++i)
      if (go[p][i]) Pre_sum(go[p][i], ret);
    sum2[p] = ret;
  }
  void build(int last, int x, int c = 0) {
    cnt = 0;
    root = create();
    Map.clear();
    if (c) {
      int p = root, d = 1;
      Hash v = Hash(0, 0);
      Map[v] = p;
      go[p][c - 1] = create();
      dfs(last, x, go[p][c - 1], v + Hash(c, c) * po[d], d + 1);
    } else
      dfs(last, x, root, Hash(0, 0), 1);
    val[root] = 0;
    long long tt = 0;
    Pre_sum(root, tt);
  }
} Trie1, Trie2;
struct Tree {
  int wei, tim, id[maxn], fa[maxd][maxn];
  Hash dtu[maxd][maxn], utd[maxd][maxn];
  int siz[maxn], path[maxn], dep[maxn];
  void get_skip_table(int x) {
    for (int j = (1), _j = (maxd - 1); j <= _j; ++j) {
      int y = fa[j - 1][x];
      int z = fa[j - 1][y];
      fa[j][x] = z;
      dtu[j][x] = dtu[j - 1][x] + dtu[j - 1][y] * po[1 << (j - 1)];
      utd[j][x] = utd[j - 1][y] + utd[j - 1][x] * po[1 << (j - 1)];
    }
  }
  int get_lca(int x, int y) {
    if (x == y) return x;
    if (id[x] > id[y]) swap(x, y);
    for (int j = (maxd - 1), _j = (0); j >= _j; --j)
      if (id[x] < id[fa[j][y]]) y = fa[j][y];
    return fa[0][y];
  }
  int skip(int x, int k) {
    for (; k; k -= (k & (-k))) {
      x = fa[__builtin_ctz(k)][x];
    }
    return x;
  }
  int move(int x, int y, int k) {
    int lca = get_lca(x, y);
    int lenx = dep[x] - dep[lca];
    int len = lenx + dep[y] - dep[lca];
    return (k <= lenx ? skip(x, k) : skip(y, len - k));
  }
  Hash get_dtu(int x, int k) {
    Hash ret = Hash(0, 0), s = Hash(1, 1);
    for (; k; k -= (k & (-k))) {
      int j = __builtin_ctz(k);
      ret = ret + dtu[j][x] * s;
      s = s * po[1 << j];
      x = fa[j][x];
    }
    return ret;
  }
  Hash get_utd(int x, int k) {
    Hash ret = Hash(0, 0);
    for (; k; k -= (k & (-k))) {
      int j = __builtin_ctz(k);
      ret = ret * po[1 << j] + utd[j][x];
      x = fa[j][x];
    }
    return ret;
  }
  void dfs(int last, int x) {
    siz[x] = 1;
    id[x] = ++tim;
    get_skip_table(x);
    for (int i = head[x]; i != -1; i = E[i].next) {
      int y = E[i].node, c = E[i].cha;
      if (y == last || bary[y]) continue;
      fa[0][y] = x;
      utd[0][y] = dtu[0][y] = Hash(c, c) * po[1];
      dep[y] = dep[x] + 1;
      path[y] = c;
      dfs(x, y);
      siz[x] += siz[y];
    }
  }
  void build(int x) {
    tim = 0;
    wei = x;
    fa[0][wei] = wei;
    utd[0][wei] = dtu[0][wei] = Hash(0, 0);
    dep[wei] = 0;
    path[wei] = 0;
    dfs(0, wei);
  }
} T0, T1;
void add_Edge(int x, int y, int c) {
  E[e_cnt] = Edge(y, head[x], c);
  head[x] = e_cnt++;
}
int compare(int x, int y, int wei) {
  int lca = T0.get_lca(x, y);
  int lenx = T0.dep[x] - T0.dep[lca];
  int len = lenx + T0.dep[y] - T0.dep[lca];
  int towei = T1.dep[x] - T1.dep[wei];
  int le = 0, ri = min(towei, len) + 1;
  while (le + 1 < ri) {
    int mid = (le + ri) >> 1;
    Hash s1 = T1.get_dtu(x, mid);
    Hash s0 = (mid <= lenx ? T0.get_dtu(x, mid)
                           : T0.get_dtu(x, lenx) +
                                 T0.get_utd(T0.skip(y, len - mid), mid - lenx) *
                                     po[lenx]);
    (s1 == s0 ? le = mid : ri = mid);
  }
  if (le == towei) return 0;
  int c1 = T1.path[T1.skip(x, le)];
  int c0 =
      (le < len
           ? T0.path[(le < lenx ? T0.skip(x, le) : T0.skip(y, len - le - 1))]
           : 0);
  return c1 - c0;
}
long long calc_cmp0(int x, int y, Trie &Tr, int &flag) {
  x = T0.move(x, y, T1.dep[x] - T1.dep[wei]);
  int lca = T0.get_lca(x, y);
  int lenx = T0.dep[x] - T0.dep[lca];
  int len = lenx + T0.dep[y] - T0.dep[lca];
  flag = (len > 0);
  int le = 0, ri = len + 1;
  while (le + 1 < ri) {
    int mid = (le + ri) >> 1;
    Hash s0 = (mid <= lenx ? T0.get_dtu(x, mid)
                           : T0.get_dtu(x, lenx) +
                                 T0.get_utd(T0.skip(y, len - mid), mid - lenx) *
                                     po[lenx]);
    (Tr.Map.find(s0) != Tr.Map.end() ? le = mid : ri = mid);
  }
  Hash s0 =
      (le <= lenx ? T0.get_dtu(x, le)
                  : T0.get_dtu(x, lenx) +
                        T0.get_utd(T0.skip(y, len - le), le - lenx) * po[lenx]);
  int c0 =
      (le < len
           ? T0.path[(le < lenx ? T0.skip(x, le) : T0.skip(y, len - le - 1))]
           : 0);
  int num = (le == 0 ? Tr.root : Tr.Map[s0]);
  long long ret = Tr.sum[num];
  if (c0 == 0) return Tr.sum[num];
  for (int i = (c0 - 1), _i = (25); i <= _i; ++i)
    if (Tr.go[num][i]) return Tr.sum[Tr.go[num][i]];
  return Tr.sum2[num];
}
void work(int last, int x, int &gg) {
  for (int i = (0), _i = (ope[x].size() - 1); i <= _i; ++i) {
    int y = ope[x][i].y, id = ope[x][i].id;
    int cmp = compare(x, y, wei);
    if (cmp < 0) {
      Ans[id] += gg;
    } else if (cmp == 0) {
      int flag;
      Ans[id] += calc_cmp0(x, y, Trie1, flag) - calc_cmp0(x, y, Trie2, flag);
      Ans[id] += flag;
    }
  }
  for (int i = head[x]; i != -1; i = E[i].next) {
    int y = E[i].node;
    if (bary[y] || y == last) continue;
    work(x, y, gg);
  }
}
void solve() {
  Trie1.build(0, wei);
  for (int i = (0), _i = (ope[wei].size() - 1); i <= _i; ++i) {
    int y = ope[wei][i].y, id = ope[wei][i].id;
    int flag;
    Ans[id] += calc_cmp0(wei, y, Trie1, flag);
  }
  for (int i = head[wei]; i != -1; i = E[i].next) {
    int y = E[i].node, c = E[i].cha;
    if (bary[y]) continue;
    Trie2.build(wei, y, c);
    int gg = T1.siz[wei] - T1.siz[y];
    work(wei, y, gg);
  }
}
void find_bary(int last, int x, int &n) {
  siz[x] = 1;
  int maxf = 0;
  for (int i = head[x]; i != -1; i = E[i].next) {
    int y = E[i].node;
    if (y == last || bary[y]) continue;
    find_bary(x, y, n);
    siz[x] += siz[y];
    maxf = max(maxf, siz[y]);
  }
  maxf = max(maxf, n - siz[x]);
  if (maxf < minf) minf = maxf, wei = x;
}
void vdc(int x, int n) {
  minf = N + 2, wei = x;
  find_bary(0, x, n);
  T1.build(wei);
  solve();
  bary[wei] = 1;
  for (int i = head[wei]; i != -1; i = E[i].next) {
    int y = E[i].node;
    if (bary[y]) continue;
    vdc(y, siz[y]);
  }
}
int main() {
  po[0] = Hash(1, 1);
  po[1] = Hash(ha1, ha2);
  for (int i = (2), _i = ((1 << maxd)); i <= _i; ++i) po[i] = po[i - 1] * po[1];
  for (; scanf("%d%d", &N, &Que) != EOF;) {
    e_cnt = 0;
    memset(head, 255, sizeof(head[0]) * (N + 2));
    for (int i = (1), _i = (N - 1); i <= _i; ++i) {
      int x, y;
      char c[5];
      scanf("%d%d%s", &x, &y, c);
      add_Edge(x, y, c[0] - 'a' + 1);
      add_Edge(y, x, c[0] - 'a' + 1);
    }
    for (int i = (1), _i = (N); i <= _i; ++i) ope[i].clear();
    for (int i = (1), _i = (Que); i <= _i; ++i) {
      int x, y;
      scanf("%d%d", &x, &y);
      ope[x].push_back(Que_Typ(y, i));
    }
    memset(bary, 0, sizeof(bary[0]) * (N + 2));
    memset(Ans, 0, sizeof(Ans[0]) * (N + 2));
    T0.build(1);
    vdc(1, N);
    for (int i = (1), _i = (Que); i <= _i; ++i) printf("%I64d\n", Ans[i]);
  }
  return 0;
}
