#include <bits/stdc++.h>
using namespace std;
char S[(long long)2e5 + 10];
int nr[(long long)2e5 + 10], N, Q, bck[19][(long long)2e5 + 10],
    poz[(long long)2e5 + 10], sol[(long long)2e5 + 10], M,
    st[(long long)2e5 + 10], tmpsol[(long long)2e5 + 10],
    mark[(long long)2e5 + 10], tmpmark[(long long)2e5 + 10],
    wh[(long long)2e5 + 10], inN[(long long)2e5 + 10], A[(long long)2e5 + 10],
    B[(long long)2e5 + 10], LCP[(long long)2e5 + 10],
    start[(long long)2e5 + 10];
long long sumK[(long long)2e5 + 10], nrK[(long long)2e5 + 10];
void suffix_array() {
  for (int i = 0; i < M; i++) st[S[i] - 'a']++;
  for (int i = 0, j = 0; i <= 'z' + 1 - 'a'; i++) {
    st[50 + i] = j;
    j += st[i];
  }
  for (int i = 0; i < M; i++) sol[st[50 + S[i] - 'a']++] = i;
  for (int i = 0, j = 0; i < M; i++) {
    if (i == 0 || S[sol[i]] != S[sol[i - 1]]) {
      j = i;
      mark[i] = 1;
    }
    bck[0][sol[i]] = j;
  }
  for (int k = 1;; k++) {
    int d = 1 << (k - 1);
    memset(st, 0, sizeof(st));
    for (int i = 0; i < M; i++)
      if (mark[i]) st[i] = i;
    memcpy(tmpmark, mark, sizeof(mark));
    for (int i = M - 1; i >= M - d; i--) {
      int b = bck[k - 1][i];
      tmpsol[st[b]] = i;
      tmpmark[st[b]++] |= 1;
    }
    for (int i = 0; i < M; i++)
      if (sol[i] - d >= 0) {
        int b = bck[k - 1][sol[i] - d];
        tmpsol[st[b]] = sol[i] - d;
        if (st[b] - 1 < 0 || tmpsol[st[b] - 1] + d >= M ||
            bck[k - 1][tmpsol[st[b] - 1] + d] != bck[k - 1][sol[i]])
          tmpmark[st[b]] = 1;
        st[b]++;
      }
    memcpy(sol, tmpsol, sizeof(sol));
    memcpy(mark, tmpmark, sizeof(mark));
    for (int i = 0, j = 0; i < M; i++) {
      if (mark[i]) j = i;
      bck[k][sol[i]] = j;
    }
    if (d * 2 > M) break;
  }
  for (int i = 0; i < M; i++) wh[sol[i]] = i;
}
int lcp(int i, int j) {
  int k = 0;
  for (; (1 << k) <= M; k++)
    ;
  int ret = 0;
  int maxret =
      min(nr[inN[i]] - (i - poz[inN[i]]), nr[inN[j]] - (j - poz[inN[j]]));
  for (k--; k >= 0 && i < M && j < M; k--)
    if (bck[k][i] == bck[k][j]) {
      i += 1 << k;
      j += 1 << k;
      ret += 1 << k;
    }
  ret = min(ret, maxret);
  return ret;
}
struct querystruct {
  int l, r, idx;
  querystruct(int l, int r, int idx) : l(l), r(r), idx(idx) {}
};
struct comp {
  bool operator()(const int& a, const int& b) const { return nr[a] < nr[b]; }
};
void update(int x, int val, int num_blocks, int target) {
  int t = x / target;
  for (int i = x; i < start[t + 1]; i++) nrK[i] += val;
  for (int k = t; k < num_blocks; k++) sumK[k] += val;
}
int query(int x, int num_blocks, int target) {
  int t = x / target, ret = 0;
  ret += t > 0 ? sumK[t - 1] : 0;
  ret += nrK[x];
  return ret;
}
int main() {
  scanf("%d %d", &N, &Q);
  for (int i = 0, j = 0; i < N; i++) {
    scanf("%s", S + M);
    nr[i] = strlen(S + M);
    poz[i] = M;
    for (int k = 0; k < nr[i]; k++) inN[M + k] = i;
    inN[M + nr[i]] = -1;
    M += nr[i];
    S[M] = 123;
    M++;
  }
  suffix_array();
  for (int i = 0; i < N; i++) {
    int x = wh[poz[i]];
    int k = 1, j = -1;
    for (; k <= x + 1; k <<= 1)
      ;
    for (; k; k >>= 1)
      if (j + k <= x && lcp(sol[j + k], sol[x]) < nr[i]) j += k;
    j++;
    A[i] = j;
    j = M;
    for (k = 1; k <= M - x; k <<= 1)
      ;
    for (; k; k >>= 1)
      if (j - k >= x && lcp(sol[j - k], sol[x]) < nr[i]) j -= k;
    j--;
    B[i] = j;
  }
  vector<vector<querystruct> > queries(N);
  vector<long long> ret(Q);
  for (int i = 0; i < Q; i++) {
    int l, r, k;
    scanf("%d %d %d", &l, &r, &k);
    l--, r--, k--;
    queries[k].push_back(querystruct(l, r, i));
  }
  int target = sqrt(M);
  for (int k = 0; k < N; k++) {
    if (nr[k] > target) {
      memset(nrK, 0, sizeof(nrK));
      memset(sumK, 0, sizeof(sumK));
      for (int i = 0; i < M; i++) {
        nrK[i] = inN[sol[i]] == k;
        if (i > 0) nrK[i] += nrK[i - 1];
      }
      for (int i = 0; i < N; i++) {
        sumK[i] = nrK[B[i]];
        if (A[i] > 0) sumK[i] -= nrK[A[i] - 1];
        if (i > 0) sumK[i] += sumK[i - 1];
      }
      for (auto& q : queries[k]) {
        int l = q.l, r = q.r, i = q.idx;
        ret[i] = sumK[r];
        ret[i] -= l > 0 ? sumK[l - 1] : 0;
      }
    }
  }
  for (int i = 1; i < M; i++) {
    LCP[i] = lcp(sol[i], sol[i - 1]);
  }
  multiset<int, comp> left;
  int num_blocks = 0;
  int oldtarget = target;
  target = sqrt(N);
  for (int i = 0; i < N;) {
    start[num_blocks++] = i;
    i += target;
  }
  start[num_blocks] = N;
  memset(nrK, 0, sizeof(nrK));
  memset(sumK, 0, sizeof(sumK));
  for (int i = 0; i < M; i++) {
    if (inN[sol[i]] == -1) continue;
    if (i > 0) {
      while (!left.empty()) {
        auto x = left.rbegin();
        if (nr[*x] <= LCP[i]) break;
        update(*x, -1, num_blocks, target);
        left.erase(next(x).base());
      }
    }
    if (sol[i] == poz[inN[sol[i]]]) {
      left.insert(inN[sol[i]]);
      update(inN[sol[i]], 1, num_blocks, target);
    }
    if (nr[inN[sol[i]]] <= oldtarget) {
      for (auto& q : queries[inN[sol[i]]]) {
        int l = q.l, r = q.r, ix = q.idx;
        ret[ix] += query(r, num_blocks, target);
        ret[ix] -= l > 0 ? query(l - 1, num_blocks, target) : 0;
      }
    }
  }
  memset(nrK, 0, sizeof(nrK));
  memset(sumK, 0, sizeof(sumK));
  left.clear();
  for (int i = M - 1; i >= 0; i--) {
    if (inN[sol[i]] == -1) continue;
    if (i < M - 1) {
      while (!left.empty()) {
        auto x = left.rbegin();
        if (nr[*x] <= LCP[i + 1]) break;
        update(*x, -1, num_blocks, target);
        left.erase(next(x).base());
      }
    }
    if (nr[inN[sol[i]]] <= oldtarget) {
      for (auto& q : queries[inN[sol[i]]]) {
        int l = q.l, r = q.r, ix = q.idx;
        ret[ix] += query(r, num_blocks, target);
        ret[ix] -= l > 0 ? query(l - 1, num_blocks, target) : 0;
      }
    }
    if (sol[i] == poz[inN[sol[i]]]) {
      left.insert(inN[sol[i]]);
      update(inN[sol[i]], 1, num_blocks, target);
    }
  }
  for_each(ret.begin(), ret.end(), [](long long& n) { printf("%I64d\n", n); });
  return 0;
}
