#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 100;
const int inf = 0x3f3f3f3f;
const int iinf = 1 << 30;
const long long linf = 2e18;
const long long mod = 1e9 + 7;
const double eps = 1e-7;
template <class T = int>
T read() {
  T f = 1, a = 0;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    a = (a << 3) + (a << 1) + ch - '0';
    ch = getchar();
  }
  return a * f;
}
int n, m, len;
char s[maxn];
int endpos[maxn];
const int unit = 19;
struct G_SAM {
  int tr[maxn * 2][26], len[maxn * 2], fail[maxn * 2], last, tot;
  int son[maxn * 50][2], rt[maxn * 50], sum[maxn * 50], dep[maxn * 50], cnt;
  int newnode(int val = unit) {
    ++cnt;
    dep[cnt] = val;
    return cnt;
  }
  void trie_insert(int now, int val) {
    sum[now]++;
    for (register int i = (unit); i >= (0); --i) {
      int bit = !!(val & (1 << i));
      if (!son[now][bit]) son[now][bit] = newnode(i - 1);
      sum[now = son[now][bit]]++;
    }
  }
  int merge(int rt1, int rt2) {
    if (!rt1 || !rt2) return rt1 + rt2;
    int new_rt = newnode(dep[rt1]);
    sum[new_rt] = sum[rt1] + sum[rt2];
    son[new_rt][0] = merge(son[rt1][0], son[rt2][0]);
    son[new_rt][1] = merge(son[rt1][1], son[rt2][1]);
    return new_rt;
  }
  int query(int now, int l, int r, int L, int R) {
    if (!now) return 0;
    if (l >= L && r <= R) return sum[now];
    int mid = (l + r) >> 1, ret = 0;
    if (L <= mid) ret += query(son[now][0], l, mid, L, R);
    if (R > mid) ret += query(son[now][1], mid + 1, r, L, R);
    return ret;
  }
  void write(int rt, int pos) {
    if (!rt) return;
    if (dep[rt] == -1) return (void)(printf("%d : %d\n", pos, sum[rt]));
    write(son[rt][0], pos), write(son[rt][1], pos + (1 << dep[rt]));
  }
  void init() {
    memset(tr, 0, sizeof(tr));
    len[0] = 0;
    rt[last = tot = 1] = newnode();
  }
  void insert(int c, int id) {
    c -= 'a';
    int p = last, np = 0, nq = 0, q = -1;
    if (!tr[p][c]) {
      rt[np = ++tot] = newnode();
      len[np] = len[p] + 1;
      for (; p && !tr[p][c]; p = fail[p]) tr[p][c] = np;
    }
    if (!p)
      fail[np] = 1;
    else {
      q = tr[p][c];
      if (len[q] == len[p] + 1)
        fail[np] = q;
      else {
        rt[nq = ++tot] = newnode();
        len[nq] = len[p] + 1;
        fail[nq] = fail[q], fail[q] = fail[np] = nq;
        memcpy(tr[nq], tr[q], sizeof(tr[nq]));
        for (; p && tr[p][c] == q; p = fail[p]) tr[p][c] = nq;
      }
    }
    last = np ? np : nq ? nq : q;
    trie_insert(rt[last], id);
  }
  int a[maxn * 2], c[maxn * 2];
  void rsort() {
    for (register int i = (1); i <= (tot); ++i) c[i] = 0;
    for (register int i = (1); i <= (tot); ++i) c[len[i]]++;
    for (register int i = (1); i <= (tot); ++i) c[i] += c[i - 1];
    for (register int i = (1); i <= (tot); ++i) a[c[len[i]]--] = i;
    for (register int i = (tot); i >= (1); --i)
      rt[fail[a[i]]] = merge(rt[fail[a[i]]], rt[a[i]]);
  }
} sam;
signed main() {
  scanf("%d %d", &n, &m);
  sam.init();
  for (register int i = (1); i <= (n); ++i) {
    scanf("%s", s + 1);
    len = strlen(s + 1);
    for (register int j = (1); j <= (len); ++j) sam.insert(s[j], i);
    endpos[i] = sam.last;
    sam.last = 1;
  }
  sam.rsort();
  for (register int i = (1); i <= (m); ++i) {
    int l, r, k;
    scanf("%d %d %d", &l, &r, &k);
    printf("%d\n",
           sam.query(sam.rt[endpos[k]], 0, (1 << (unit + 1)) - 1, l, r));
  }
  return 0;
}
