#include <bits/stdc++.h>
using namespace std;
string x[100005];
long long T, n, Q, ans[100005], rt[100005], block = 400, sum[100005];
struct BIT {
  long long tree[100010];
  long long lowbit(long long x) { return x & -x; }
  void update(long long x, long long val) {
    while (x <= T) {
      tree[x] += val;
      x += lowbit(x);
    }
  }
  long long query(long long x) {
    long long ans = 0;
    while (x) {
      ans += tree[x];
      x -= lowbit(x);
    }
    return ans;
  }
  void clear() { memset(tree, 0, sizeof(tree)); }
} tree;
struct ACAM {
  long long tree[100005][26], tot, fail[100005], head[100005], nxt[100005],
      pnt[100005];
  long long E, siz[100005], dfn[100005];
  long long insert(string x) {
    long long p = 0;
    for (long long i = 0; i < x.length(); i++) {
      if (!tree[p][x[i] - 'a']) tree[p][x[i] - 'a'] = ++tot;
      p = tree[p][x[i] - 'a'];
    }
    return p;
  }
  void build() {
    queue<long long> q;
    for (long long i = 0; i < 26; i++)
      if (tree[0][i]) q.push(tree[0][i]);
    while (!q.empty()) {
      long long u = q.front();
      q.pop();
      for (long long i = 0; i < 26; i++) {
        if (!tree[u][i])
          tree[u][i] = tree[fail[u]][i];
        else {
          fail[tree[u][i]] = tree[fail[u]][i];
          q.push(tree[u][i]);
        }
      }
    }
  }
  void add_edge(long long u, long long v) {
    pnt[E] = v;
    nxt[E] = head[u];
    head[u] = E++;
  }
  void dfs(long long u) {
    dfn[u] = ++T;
    siz[u] = 1;
    for (long long i = head[u]; i != -1; i = nxt[i]) {
      long long v = pnt[i];
      dfs(v);
      siz[u] += siz[v];
    }
  }
  void init() {
    build();
    memset(head, -1, sizeof(head));
    for (long long i = 1; i <= tot; i++) add_edge(fail[i], i);
    dfs(0);
  }
  long long query(string x) {
    long long p = 0, ans = 0;
    for (long long i = 0; i < x.length(); i++) {
      p = tree[p][x[i] - 'a'];
      ans += ::tree.query(dfn[p]);
    }
    return ans;
  }
} AC;
struct node {
  long long opt, id, maxn, k;
  bool operator<(const node &x) const { return maxn < x.maxn; }
};
vector<node> V;
vector<node> V1[100005];
signed main() {
  cin >> n >> Q;
  for (long long i = 1; i <= n; i++) cin >> x[i];
  for (long long i = 1; i <= n; i++) rt[i] = AC.insert(x[i]);
  AC.init();
  for (long long i = 1; i <= Q; i++) {
    long long l, r, k;
    cin >> l >> r >> k;
    l--;
    if (x[k].length() <= block) {
      if (l) V.push_back((node){-1, i, l, k});
      V.push_back((node){1, i, r, k});
    } else
      V1[k].push_back((node){0, l, r, i});
  }
  sort(V.begin(), V.end());
  long long now = 0;
  for (long long i = 1; i <= n; i++) {
    tree.update(AC.dfn[rt[i]], 1);
    tree.update(AC.dfn[rt[i]] + AC.siz[rt[i]], -1);
    while (now != V.size() && V[now].maxn == i) {
      ans[V[now].id] += V[now].opt * AC.query(x[V[now].k]);
      now++;
    }
  }
  for (long long i = 1; i <= n; i++) {
    if (V1[i].size()) {
      tree.clear();
      memset(sum, 0, sizeof(sum));
      long long p = 0;
      for (long long j = 0; j < x[i].size(); j++) {
        p = AC.tree[p][x[i][j] - 'a'];
        tree.update(AC.dfn[p], 1);
      }
      for (long long j = 1; j <= n; j++)
        sum[j] = sum[j - 1] + tree.query(AC.dfn[rt[j]] + AC.siz[rt[j]] - 1) -
                 tree.query(AC.dfn[rt[j]] - 1);
      for (long long j = 0; j < V1[i].size(); j++)
        ans[V1[i][j].k] = sum[V1[i][j].maxn] - sum[V1[i][j].id];
    }
  }
  for (long long i = 1; i <= Q; i++) cout << ans[i] << '\n';
}
