对所有的串加特殊字符隔开,单串建立后缀自动机。然后将每个的fa边反向建树,对树dfs得到dfs序,对dfs序建立线段树。询问离线,每个询问拆成1-(l-1)和1-r。。。按端点排序,然后每次加入线段树,查询k对应的节点的子树和。。。
#include <iostream> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <algorithm> #include <cstring> #include <climits> #include <cstdlib> #include <cmath> #include <time.h> #define maxn 800005 #define maxm 1000005 #define eps 1e-12 #define mod 1000003 #define INF 0x3f3f3f3f #define PI (acos(-1.0)) #define lowbit(x) (x&(-x)) #define mp make_pair #define ls o<<1 #define rs o<<1 | 1 #define lson o<<1, L, mid #define rson o<<1 | 1, mid+1, R #pragma comment(linker, "/STACK:102400000,102400000") #define pii pair<int, int> typedef long long LL; typedef unsigned long long ULL; //typedef int LL; using namespace std; LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;} LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;} // head const int alpha = 27; struct node { int len, k; node *next[alpha], *fa; }*h[maxn], *tail, *last, *root, pool[maxm]; struct Edge { int v; Edge *next; }E[maxm], *H[maxn], *edges; struct qu { int w, t, id, flag; qu(int w = 0, int t = 0, int id = 0, int flag = 0) : w(w), t(t), id(id), flag(flag) {} }q[maxm]; vector<int> vec[maxn]; int sum[maxn << 2]; int in[maxn]; int out[maxn]; int res[maxm]; string s[maxn]; int n, m, dfs_clock; void addedges(int u, int v) { edges->v = v; edges->next = H[u]; H[u] = edges++; } node* newnode(int len, int k) { tail->len = len; tail->k = k; tail->fa = 0; memset(tail->next, 0, sizeof tail->next); return tail++; } void add(int c, int k) { node *p = last, *np = newnode(p->len+1, k); last = np; for(; p && !p->next[c]; p = p->fa) p->next[c] = np; if(!p) np->fa = root; else { node *q = p->next[c]; if(p->len + 1 == q->len) np->fa = q; else { node *nq = newnode(0, 0); *nq = *q; nq->len = p->len + 1; q->fa = np->fa = nq; for(; p && p->next[c] == q; p = p->fa) p->next[c] = nq; } } } void init() { dfs_clock = 0; edges = E; tail = pool; last = root = newnode(0, 0); memset(H, 0, sizeof H); memset(res, 0, sizeof res); } int cmp(qu a, qu b) { return a.w < b.w; } void DFS(int u) { in[u] = ++dfs_clock; for(Edge *e = H[u]; e; e = e->next) DFS(e->v); out[u] = dfs_clock; } void pushup(int o) { sum[o] = sum[ls] + sum[rs]; } void build(int o, int L, int R) { sum[o] = 0; if(L == R) return; int mid = (L + R) >> 1; build(lson); build(rson); } int query(int o, int L, int R, int ql, int qr) { if(ql <= L && qr >= R) return sum[o]; int mid = (L + R) >> 1, ans = 0; if(ql <= mid) ans += query(lson, ql, qr); if(qr > mid) ans += query(rson, ql, qr); return ans; } void updata(int o, int L, int R, int v) { if(L == R) { sum[o]++; return; } int mid = (L + R) >> 1; if(v <= mid) updata(lson, v); else updata(rson, v); pushup(o); } void work() { for(int i = 0; i <= n; i++) vec[i].clear(); for(int i = 1; i <= n; i++) { cin >> s[i]; if(i != 1) add(26, 0); for(int j = 0; s[i][j]; j++) { add(s[i][j] - 'a', i); vec[last->k].push_back(last - root); } } for(int i = 1; i <= n; i++) { h[i] = root; for(int j = 0; s[i][j]; j++) h[i] = h[i]->next[s[i][j] - 'a']; } for(node *p = pool + 1; p < tail; p++) addedges(p->fa - root, p - root); DFS(0); int tot = tail - pool; int cnt = 0, l, r, kk; for(int i = 1; i <= m; i++) { scanf("%d%d%d", &l, &r, &kk); q[cnt++] = qu(l-1, h[kk] - root, i, -1); q[cnt++] = qu(r, h[kk] - root, i, 1); } sort(q, q+cnt, cmp); build(1, 1, dfs_clock); int j = 0; while(q[j].w <= 0 && j < cnt) { res[q[j].id] += query(1, 1, dfs_clock, in[q[j].t], out[q[j].t]) * q[j].flag; j++; } for(int i = 1; i <= n; i++) { for(int l = 0; l < vec[i].size(); l++) updata(1, 1, dfs_clock, in[vec[i][l]]); while(q[j].w <= i && j < cnt) { res[q[j].id] += query(1, 1, dfs_clock, in[q[j].t], out[q[j].t]) * q[j].flag; j++; } } for(int i = 1; i <= m; i++) printf("%d\n", res[i]); } int main() { while(scanf("%d%d", &n, &m)!=EOF) { init(); work(); } return 0; }