#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;   }