#include <bits/stdc++.h>   using namespace std;   struct vertex {     map<char, int> next, go;     int p, link;     char pch;     vector<int> leaf;     unordered_set<int> visited;     vertex(int p = -1, char pch = -1) : p(p), pch(pch), link(-1) {}   };   vector<vertex> t;   void aho_init() {     t.clear();     t.push_back(vertex());   }   int add_string(string s, int id) {     int v = 0;     for (char c : s) {       if (!t[v].next.count(c)) {         t[v].next[c] = t.size();         t.push_back(vertex(v, c));       }       v = t[v].next[c];     }     t[v].leaf.push_back(id);     return v;   }   void add_visited(int v, int id) { t[v].visited.insert(id); }   int go(int v, char c);   int get_link(int v) {     if (t[v].link < 0)       if (!v || !t[v].p)         t[v].link = 0;       else         t[v].link = go(get_link(t[v].p), t[v].pch);     return t[v].link;   }   int go(int v, char c) {     if (!t[v].go.count(c))       if (t[v].next.count(c))         t[v].go[c] = t[v].next[c];       else         t[v].go[c] = v == 0 ? 0 : go(get_link(v), c);     return t[v].go[c];   }   const int N = 3e5;   vector<int> g[N];   int last[N];   string s[N];   int n, q, B;   long long tot[400], sum[N];   struct Query {     int l, r, k, id;   };   int dfs(int x, int i, vector<long long>& partials) {     int cnt = 0;     if (t[x].visited.count(i)) ++cnt, t[x].visited.erase(i);     for (auto v : g[x]) cnt += dfs(v, i, partials);     for (auto v : t[x].leaf) partials[v] += cnt;     return cnt;   }   void solveLarge(vector<Query>& q, int i, vector<long long>& res) {     vector<long long> partials(n + 1, 0);     dfs(0, i, partials);     for (int i = 1; i < n + 1; i++) partials[i] += partials[i - 1];     for (auto query : q) {       res[query.id] = partials[query.r] - partials[query.l];     }   }   void add(int i, int val) {     while (i < N && i % B) {       sum[i++] += val;     }     i /= B;     while (i <= n / B) tot[i++] += val;   }   int get(int i) { return sum[i] + tot[i / B]; }   void dfs2(int x, vector<vector<Query>>& queries, vector<long long>& res) {     for (auto v : t[x].leaf) add(v, 1);     for (auto v : t[x].visited) {       for (auto q : queries[v]) {         res[q.id] += get(q.r) - get(q.l);       }     }     for (auto v : g[x]) dfs2(v, queries, res);     for (auto v : t[x].leaf) add(v, -1);   }   void solveSmall(vector<vector<Query>>& queries, vector<long long>& res) {     dfs2(0, queries, res);   }   int main() {     cin >> n >> q;     B = sqrt(n);     for (int i = 0; i < n; i++) cin >> s[i];     aho_init();     for (int i = 0; i < n; i++) {       add_string(s[i], i + 1);     }     for (int i = 0; i < n; i++) {       int cur = 0;       add_visited(cur, i);       for (char c : s[i]) {         cur = go(cur, c);         add_visited(cur, i);       }       last[i] = cur;     }     for (int i = 1; i < ((int)t.size()); i++) {       g[get_link(i)].push_back(i);     }     vector<Query> queries;     for (int i = 0; i < q; i++) {       int l, r, k;       cin >> l >> r >> k;       queries.push_back({l - 1, r, k - 1, i});     }     vector<vector<Query>> large(n);     vector<vector<Query>> small(n);     for (auto query : queries) {       if (((int)s[query.k].size()) >= B) {         large[query.k].push_back(query);       } else {         small[query.k].push_back(query);       }     }     vector<long long> res(q, 0);     for (int i = 0; i < n; i++) {       if (((int)large[i].size())) solveLarge(large[i], i, res);     }     solveSmall(small, res);     for (int i = 0; i < q; i++) cout << res[i] << endl;     return 0;   }