#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4e5 + 5;
const int MAXQ = 5e5 + 5;
const int MAXP = 8e6 + 5;
template <typename T>
void chkmax(T &x, T y) {
  x = max(x, y);
}
template <typename T>
void chkmin(T &x, T y) {
  x = min(x, y);
}
template <typename T>
void read(T &x) {
  x = 0;
  int f = 1;
  char c = getchar();
  for (; !isdigit(c); c = getchar())
    if (c == '-') f = -f;
  for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
  x *= f;
}
template <typename T>
void write(T x) {
  if (x < 0) x = -x, putchar('-');
  if (x > 9) write(x / 10);
  putchar(x % 10 + '0');
}
template <typename T>
void writeln(T x) {
  write(x);
  puts("");
}
struct SegmentTreeMerging {
  struct Node {
    int lc, rc, sum;
    bool leaf;
  } a[MAXP];
  int size, n;
  void init(int x) {
    n = x;
    size = 0;
  }
  void update(int root) { a[root].sum = a[a[root].lc].sum + a[a[root].rc].sum; }
  void modify(int &root, int l, int r, int pos, int d) {
    if (root == 0) root = ++size;
    if (l == r) {
      a[root].sum += d;
      a[root].leaf = true;
      return;
    }
    int mid = (l + r) / 2;
    if (mid >= pos)
      modify(a[root].lc, l, mid, pos, d);
    else
      modify(a[root].rc, mid + 1, r, pos, d);
    update(root);
  }
  void modify(int &root, int val, int d) { modify(root, 1, n, val, d); }
  int merge(int x, int y) {
    if (x == 0 || y == 0) return x + y;
    if (a[x].leaf) {
      a[x].sum += a[y].sum;
      return x;
    }
    a[x].lc = merge(a[x].lc, a[y].lc);
    a[x].rc = merge(a[x].rc, a[y].rc);
    update(x);
    return x;
  }
  void join(int &to, int from) { to = merge(to, from); }
  int query(int root, int l, int r, int ql, int qr) {
    if (root == 0) return 0;
    if (l == ql && r == qr) return a[root].sum;
    int mid = (l + r) / 2, ans = 0;
    if (mid >= ql) ans += query(a[root].lc, l, mid, ql, min(mid, qr));
    if (mid + 1 <= qr)
      ans += query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);
    return ans;
  }
  int query(int root, int l, int r) { return query(root, 1, n, l, r); }
} ST;
struct SuffixAutomaton {
  struct Node {
    int child[26];
    int father, depth;
  } a[MAXN];
  vector<int> e[MAXN];
  vector<int> home[MAXN];
  vector<pair<int, int>> s[MAXN];
  int n, root, size, last;
  int newnode(int dep) {
    a[++size].depth = dep;
    return size;
  }
  void init() {
    size = 0;
    root = last = 0;
  }
  void extend(int ch) {
    int p = last, np;
    if (a[p].child[ch]) {
      int q = a[p].child[ch];
      if (a[p].depth + 1 == a[q].depth)
        np = q;
      else {
        np = newnode(a[p].depth + 1);
        memcpy(a[np].child, a[q].child, sizeof(a[q].child));
        a[np].father = a[q].father;
        a[q].father = np;
        while (a[p].child[ch] == q) {
          a[p].child[ch] = np;
          p = a[p].father;
        }
      }
    } else {
      np = newnode(a[p].depth + 1);
      while (a[p].child[ch] == 0) {
        a[p].child[ch] = np;
        p = a[p].father;
      }
      if (a[p].child[ch] == np)
        a[np].father = root;
      else {
        int q = a[p].child[ch];
        if (a[q].depth == a[p].depth + 1)
          a[np].father = q;
        else {
          int nq = newnode(a[p].depth + 1);
          memcpy(a[nq].child, a[q].child, sizeof(a[q].child));
          a[nq].father = a[q].father;
          a[q].father = a[np].father = nq;
          while (a[p].child[ch] == q) {
            a[p].child[ch] = nq;
            p = a[p].father;
          }
        }
      }
    }
    last = np;
  }
  void insert(char *s) {
    last = 0, n++;
    int len = strlen(s + 1);
    for (int i = 1; i <= len; i++) {
      extend(s[i] - 'a');
      home[n].push_back(last);
    }
  }
  int rt[MAXN], ans[MAXQ];
  vector<pair<pair<int, int>, int>> q[MAXN];
  void work(int pos) {
    for (auto x : s[pos]) ST.modify(rt[pos], x.first, x.second);
    for (auto x : e[pos]) {
      work(x);
      ST.join(rt[pos], rt[x]);
    }
    for (auto x : q[pos])
      ans[x.second] = ST.query(rt[pos], x.first.first, x.first.second);
  }
  void solve(int m) {
    for (int i = 1; i <= size; i++) e[a[i].father].push_back(i);
    for (int i = 1; i <= n; i++)
      for (unsigned j = 0; j < home[i].size(); j++)
        s[home[i][j]].emplace_back(i, 1);
    work(0);
    for (int i = 1; i <= m; i++) writeln(ans[i]);
  }
} SAM;
char s[MAXN];
int main() {
  int n, m;
  read(n), read(m);
  SAM.init(), ST.init(n);
  for (int i = 1; i <= n; i++) {
    scanf("\n%s", s + 1);
    SAM.insert(s);
  }
  for (int i = 1; i <= m; i++) {
    int l, r, k;
    read(l), read(r), read(k);
    SAM.q[SAM.home[k].back()].emplace_back(make_pair(l, r), i);
  }
  SAM.solve(m);
  return 0;
}
