#include <bits/stdc++.h>
using namespace std;
int tree[300005 * 20], lefto[300005 * 20], righto[300005 * 20], nw;
struct ext {
  int len, link;
  map<char, int> next;
};
ext st[300005];
int sz, last;
void sa_init() {
  sz = last = 0;
  st[0].len = 0;
  st[0].link = -1;
  ++sz;
}
int update(int node, int st, int en, int g) {
  int ps = ++nw;
  if (st == en) {
    tree[ps] = tree[node] + 1;
    return ps;
  }
  lefto[ps] = lefto[node];
  righto[ps] = righto[node];
  int mid = (st + en) >> 1;
  if (g <= mid)
    lefto[ps] = update(lefto[node], st, mid, g);
  else
    righto[ps] = update(righto[node], mid + 1, en, g);
  tree[ps] = tree[lefto[ps]] + tree[righto[ps]];
  return ps;
}
int query(int node, int node2, int st, int en, int l, int r) {
  if (st >= l and en <= r) return tree[node] - tree[node2];
  int mid = (st + en) >> 1;
  int ret = 0;
  if (l <= mid) ret += query(lefto[node], lefto[node2], st, mid, l, r);
  if (r > mid) ret += query(righto[node], righto[node2], mid + 1, en, l, r);
  return ret;
}
int dp[300005][26];
int extend(char c, int last) {
  if (dp[last][c - 97] != -1) return dp[last][c - 97];
  int cur = sz++;
  st[cur].len = st[last].len + 1;
  int p;
  for (p = last; p != -1 && !st[p].next.count(c); p = st[p].link)
    st[p].next[c] = cur;
  if (p == -1)
    st[cur].link = 0;
  else {
    int q = st[p].next[c];
    if (st[p].len + 1 == st[q].len)
      st[cur].link = q;
    else {
      int clone = sz++;
      st[clone].len = st[p].len + 1;
      st[clone].next = st[q].next;
      st[clone].link = st[q].link;
      for (; p != -1 && st[p].next[c] == q; p = st[p].link)
        st[p].next[c] = clone;
      st[q].link = st[cur].link = clone;
    }
  }
  return dp[last][c - 97] = cur;
}
struct st2 {
  int g, lev, id, bol;
  st2() {}
  st2(int _g, int _lev, int _id, int _bol) {
    g = _g;
    lev = _lev;
    id = _id;
    bol = _bol;
  }
};
int top[300005], P[300005];
vector<st2> danda[300005];
void upchain(int lev, int node, int c) {
  while (node) {
    if (st[node].len == 0) return;
    int g = lev - st[node].len;
    assert(g >= 1);
    if (c == -1) g = 1e8;
    danda[top[node]].push_back(st2(g, lev, -1, -1));
    node = P[top[node]];
  }
}
int mini(int v) {
  if (v == 0) return 0;
  return st[st[v].link].len + 1;
}
void query_chain(int node, int lev, int lc, int q, int bol, int len) {
  while (node) {
    int k = min(st[node].len, len);
    if (k == 0) return;
    int g = min(lc + k, lev);
    danda[top[node]].push_back(st2(lc, g, q, bol));
    node = P[top[node]];
  }
}
int pos, start[300005], endo[300005];
struct st1 {
  int node, lev, id;
  st1() {}
  st1(int _node, int _lev, int _id) {
    node = _node;
    lev = _lev;
    id = _id;
  }
};
vector<st1> ques[300005];
struct st3 {
  int id, bol, node, lc;
  st3() {}
  st3(int _node, int _lc, int _id, int _bol) {
    node = _node;
    lc = _lc;
    id = _id;
    bol = _bol;
  }
};
vector<st3> half[300005];
vector<int> liqu[300005];
int root[300005], ans[300005];
vector<int> vc[300005];
vector<char> cost[300005];
void dfs(int v, int par, int prev, char c, int lev) {
  root[lev] = root[lev - 1];
  if (v > 1) {
    prev = st[prev].next[c];
    assert(prev != 0);
    root[lev] = update(root[lev], 1, pos, start[prev]);
    upchain(lev, prev, 1);
  }
  for (int i = 0; i < ques[v].size(); i++) {
    int nd = ques[v][i].node;
    int le = ques[v][i].lev;
    int id = ques[v][i].id;
    int g = query(root[lev], root[le - 1], 1, pos, start[nd], endo[nd]);
    ans[id] += g;
  }
  for (int i = 0; i < half[v].size(); i++) {
    int id = half[v][i].id;
    int bol = half[v][i].bol;
    int node = half[v][i].node;
    int lc = half[v][i].lc;
    query_chain(node, lev, lc, id, bol, liqu[v][i]);
  }
  for (int i = 0; i < vc[v].size(); i++) {
    int w = vc[v][i];
    if (w == par) continue;
    dfs(w, v, prev, cost[v][i], lev + 1);
  }
  if (v > 1) {
    upchain(lev, prev, -1);
  }
}
int bap[300005][20], L[300005], len;
void dfs2(int v, int par, char c, int last, int lev) {
  bap[v][0] = par;
  L[v] = lev;
  len = max(len, lev);
  if (v > 1) {
    last = extend(c, last);
  }
  for (int i = 0; i < vc[v].size(); i++) {
    int w = vc[v][i];
    if (w == par) continue;
    dfs2(w, v, cost[v][i], last, lev + 1);
  }
}
int maxi[300005], siz[300005];
vector<int> ac[300005];
void dfs3(int v) {
  start[v] = ++pos;
  maxi[v] = -1;
  for (int i = 0; i < ac[v].size(); i++) {
    int w = ac[v][i];
    dfs3(w);
    if (maxi[v] == -1)
      maxi[v] = w;
    else if (siz[maxi[v]] < siz[w]) {
      maxi[v] = w;
    }
    siz[v] += siz[w];
  }
  endo[v] = pos;
  siz[v]++;
}
void hld(int v, int par, int r) {
  if (r == -1)
    top[v] = v;
  else
    top[v] = r;
  P[v] = par;
  if (maxi[v] != -1) hld(maxi[v], v, top[v]);
  for (int i = 0; i < ac[v].size(); i++) {
    int w = ac[v][i];
    if (w == maxi[v]) continue;
    hld(w, v, -1);
  }
}
int tree2[300005 * 20];
void update2(int node, int st, int en, int l, int g) {
  if (st == en) {
    tree2[node] = g;
    return;
  }
  int mid = (st + en) >> 1;
  if (l <= mid)
    update2(node * 2, st, mid, l, g);
  else
    update2(node * 2 + 1, mid + 1, en, l, g);
  tree2[node] = min(tree2[node * 2], tree2[node * 2 + 1]);
}
int query2(int node, int st, int en, int g, int l) {
  if (tree2[node] > g) return -1;
  if (st > l) return -1;
  if (st == en) {
    return st;
  }
  int mid = (st + en) >> 1;
  int r = query2(node * 2 + 1, mid + 1, en, g, l);
  if (r > -1) return r;
  return query2(node * 2, st, mid, g, l);
}
int create[300005][2];
void sim(st2 ps) {
  int lev = ps.lev;
  int g = ps.g;
  int ans = query2(1, 1, len, g, lev);
  if (ans > lev || ans <= g) return;
  int id = ps.id;
  int bol = ps.bol;
  create[id][bol] = max(create[id][bol], ans - g);
}
void simulation(int n) {
  for (int i = 0; i < n; i++) {
    if (danda[i].size() == 0) continue;
    for (int j = 0; j < danda[i].size(); j++) {
      if (danda[i][j].bol >= 0) {
        sim(danda[i][j]);
        continue;
      }
      int lev = danda[i][j].lev;
      int g = danda[i][j].g;
      update2(1, 1, len, lev, g);
    }
  }
}
int beg[300005][2], en[300005][2], obo[2];
vector<int> trie[2][300005];
void dfs5(int v, int bol) {
  beg[v][bol] = ++obo[bol];
  for (int i = 0; i < trie[bol][v].size(); i++) {
    int w = trie[bol][v][i];
    dfs5(w, bol);
  }
  en[v][bol] = obo[bol];
}
vector<int> sub[300005];
int update3(int node, int st, int en, int l, int r) {
  int ps = ++nw;
  assert(nw < 300005 * 20);
  tree[ps] = tree[node];
  lefto[ps] = lefto[node];
  righto[ps] = righto[node];
  if (st >= l and en <= r) {
    tree[ps] += 1;
    return ps;
  }
  int mid = (st + en) >> 1;
  if (mid >= l) lefto[ps] = update3(lefto[node], st, mid, l, r);
  if (mid < r) righto[ps] = update3(righto[node], mid + 1, en, l, r);
  return ps;
}
int vis2[300005], casio = 1;
void run_sim(int v, int par) {
  root[v] = root[par];
  for (int i = 0; i < sub[v].size(); i++) {
    int w = sub[v][i];
    root[v] = update3(root[v], 1, obo[1], beg[w][1], en[w][1]);
  }
  for (int i = 0; i < trie[0][v].size(); i++) {
    int w = trie[0][v][i];
    if (vis2[w] != casio) continue;
    run_sim(w, v);
  }
}
int query3(int node, int st, int en, int l) {
  int ret = tree[node];
  if (st == en) return ret;
  int mid = (st + en) >> 1;
  if (l <= mid)
    ret += query3(lefto[node], st, mid, l);
  else
    ret += query3(righto[node], mid + 1, en, l);
  return ret;
}
unordered_map<long long, int> name[2];
int cnt[2];
int prime[] = {103, 10007};
int mod = 784568360, mod2 = 820925358;
int crt(int sum, int sum2, int bol) {
  long long ff = 1LL * sum * mod2 + sum2;
  if (name[bol][ff] == 0) {
    name[bol][ff] = ++cnt[bol];
  }
  return name[bol][ff];
}
int lps[300005];
vector<int> linear[2][300005];
int vis[300005][2];
void func(string pat, int bol, int id) {
  int M = pat.size();
  linear[bol][id].resize(M + 2);
  long long sum = 0, sum2 = 0;
  for (int i = 0; i < M; i++) {
    sum = sum * prime[0] + pat[i] - 96;
    sum %= mod;
    sum2 = sum2 * prime[1] + pat[i] - 96;
    sum2 %= mod2;
    int g = crt(sum, sum2, bol);
    linear[bol][id][i + 1] = g;
  }
  int len = 0;
  lps[0] = 0;
  int i = 1;
  while (i < M) {
    if (pat[i] == pat[len]) {
      len++;
      lps[i] = len;
      i++;
    } else {
      if (len != 0) {
        len = lps[len - 1];
      } else {
        lps[i] = 0;
        i++;
      }
    }
  }
  for (int i = 0; i < M; i++) {
    int r = linear[bol][id][i + 1];
    if (vis[r][bol]) continue;
    vis[r][bol] = 1;
    int g = lps[i];
    int x = linear[bol][id][g];
    trie[bol][x].push_back(r);
  }
}
void init(int n) {
  for (int j = 1; (1 << j) <= n; j++)
    for (int i = 1; i <= n; i++)
      if (bap[i][j - 1] != -1) bap[i][j] = bap[bap[i][j - 1]][j - 1];
}
int lca_query(int p, int q) {
  int tmp, log, i;
  if (L[p] < L[q]) tmp = p, p = q, q = tmp;
  log = 1;
  while (1) {
    int next = log + 1;
    if ((1 << next) > L[p]) break;
    log++;
  }
  for (i = log; i >= 0; i--)
    if (L[p] - (1 << i) >= L[q]) p = bap[p][i];
  if (p == q) return p;
  for (i = log; i >= 0; i--)
    if (bap[p][i] != -1 && bap[p][i] != bap[q][i]) p = bap[p][i], q = bap[q][i];
  return bap[p][0];
}
string my[300005];
char str2[300005];
int hf[300005][2], dir[300005][2], lin[300005][2];
int qui[300005];
map<string, int> coun;
int ara[300005];
vector<int> temp[300005];
int main() {
  int i, j, k, l, m, n, q, ff;
  for (int i = 1; i < 300005 * 20; i++) tree2[i] = 1e8;
  memset(dp, -1, sizeof dp);
  scanf("%d%d%d", &n, &m, &q);
  for (int i = 0; i < n - 1; i++) {
    scanf("%d%d%s", &l, &k, str2);
    vc[l].push_back(k);
    vc[k].push_back(l);
    cost[l].push_back(str2[0]);
    cost[k].push_back(str2[0]);
  }
  sa_init();
  memset(bap, -1, sizeof bap);
  dfs2(1, -1, 0, 0, 1);
  for (int kk = 1; kk <= m; kk++) {
    scanf("%s", str2);
    my[kk] += str2;
    int l = strlen(str2);
    int cur = 0;
    int ck = 1, len = 0;
    for (int i = l - 1; i >= 0; i--) {
      char c = str2[i];
      int prv = len;
      if (st[cur].next.find(c) == st[cur].next.end())
        ck = 0;
      else {
        len++;
        cur = st[cur].next[c];
        continue;
      }
      while (cur > -1 && st[cur].next.find(c) == st[cur].next.end()) {
        cur = st[cur].link;
      }
      if (cur == -1) {
        len = 0;
        cur = 0;
        continue;
      }
      len = min(st[cur].len, prv);
      len++;
      cur = st[cur].next[c];
    }
    hf[kk][0] = cur;
    lin[kk][0] = len;
    if (ck == 0) cur = 0;
    dir[kk][0] = cur;
    cur = 0, ck = 1, len = 0;
    for (int i = 0; str2[i]; i++) {
      char c = str2[i];
      int prv = len;
      if (st[cur].next.find(c) == st[cur].next.end())
        ck = 0;
      else {
        len++;
        cur = st[cur].next[c];
        continue;
      }
      while (cur > -1 && st[cur].next.find(c) == st[cur].next.end()) {
        cur = st[cur].link;
      }
      if (cur == -1) {
        len = 0;
        cur = 0;
        continue;
      }
      len = min(st[cur].len, prv);
      len++;
      cur = st[cur].next[c];
    }
    hf[kk][1] = cur;
    lin[kk][1] = len;
    if (ck == 0) cur = 0;
    dir[kk][1] = cur;
  }
  init(n);
  for (int i = 1; i < sz; i++) {
    ac[st[i].link].push_back(i);
  }
  dfs3(0);
  hld(0, 0, -1);
  for (int i = 1; i <= q; i++) {
    scanf("%d%d%d", &l, &k, &j);
    qui[i] = j;
    int lc = lca_query(l, k);
    if (l == lc) {
      int x = L[lc] + my[j].size();
      if (dir[j][1] && x <= L[k]) ques[k].push_back(st1(dir[j][1], x, i));
      continue;
    }
    if (k == lc) {
      int x = L[lc] + my[j].size();
      if (dir[j][0] && x <= L[l]) ques[l].push_back(st1(dir[j][0], x, i));
      continue;
    }
    int x = L[lc] + my[j].size();
    if (dir[j][0] && x <= L[l]) ques[l].push_back(st1(dir[j][0], x, i));
    if (dir[j][1] && x <= L[k]) {
      ques[k].push_back(st1(dir[j][1], x, i));
    }
    if (hf[j][0])
      half[l].push_back(st3(hf[j][0], L[lc], i, 0)),
          liqu[l].push_back(lin[j][0]);
    if (hf[j][1])
      half[k].push_back(st3(hf[j][1], L[lc], i, 1)),
          liqu[k].push_back(lin[j][1]);
  }
  dfs(1, -1, 0, 0, 1);
  simulation(sz);
  for (int i = 1; i <= m; i++) {
    long long sum = 0, sum2 = 0;
    func(my[i], 0, i);
    reverse(my[i].begin(), my[i].end());
    func(my[i], 1, i);
  }
  for (int i = 0; i <= nw; i++) {
    tree[i] = 0;
    lefto[i] = 0;
    righto[i] = 0;
  }
  nw = 0;
  dfs5(0, 0);
  dfs5(0, 1);
  for (int i = 1; i <= q; i++) {
    if (create[i][0] == 0 || create[i][1] == 0) continue;
    j = qui[i];
    temp[j].push_back(i);
  }
  for (int i = 1; i <= m; i++) {
    l = my[i].size();
    casio++;
    vector<int> tp;
    for (int j = 1; j < l; j++) {
      int g = linear[0][i][j];
      tp.push_back(g);
      int h = linear[1][i][l - j];
      vis2[g] = casio;
      sub[g].push_back(h);
    }
    int g = linear[0][i][l];
    vis2[g] = casio;
    tp.push_back(g);
    run_sim(0, 0);
    for (j = 0; j < temp[i].size(); j++) {
      int q = temp[i][j];
      int g = linear[0][i][create[q][0]];
      int h = linear[1][i][create[q][1]];
      ans[q] += query3(root[g], 1, obo[1], beg[h][1]);
    }
    for (int j = 0; j < tp.size(); j++) {
      int w = tp[j];
      sub[w].clear();
    }
    for (int j = 0; j <= nw; j++) {
      tree[j] = 0;
      lefto[j] = 0;
      righto[j] = 0;
    }
    nw = 0;
  }
  for (int i = 1; i <= q; i++) {
    printf("%d\n", ans[i]);
  }
}
