本来想找\(01Trie\)的结果找到了一堆字典树水题。。。算了算了当水个提交量好了。
直接插入模式串,维护一个\(Trie\)树的子树\(sum\)大小,求解每一个文本串匹配时走过的链上匹配数和终点处的子树大小之和。
#include using namespace std;int top, sta[10010];int n, m, l, s[10010], max_size;int ch[500010][2], sz[500010], sum[500010];void push_up (int p) { sz[p] = sum[p]; if (ch[p][0]) sz[p] += sz[ch[p][0]]; if (ch[p][1]) sz[p] += sz[ch[p][1]];}void add_str () { int now = 0; sta[top = 1] = 0; for (int i = 1; i <= l; ++i) { if (!ch[now][s[i]]) { ch[now][s[i]] = ++max_size; } // printf ("ch[%d][%d] = %d\n", now, s[i], ch[now][s[i]]); now = ch[now][s[i]]; sta[++top] = now; } sz[now]++; sum[now]++; while (top > 0) push_up (sta[top--]);}int get_str () { int now = 0, ans = 0; for (int i = 1; i <= l; ++i) { if (!ch[now][s[i]]) { return ans; } // printf ("now = %d, sum[now] = %d sz[now] = %d\n", now, sum[now], sz[now]); now = ch[now][s[i]]; ans += sum[now]; } // printf ("now = %d\n", now); ans += sz[now] - sum[now]; return ans;}int main () { cin >> m >> n; for (int i = 1; i <= m; ++i) { scanf ("%d", &l); for (int j = 1; j <= l; ++j) { scanf ("%d", &s[j]); } add_str (); } for (int i = 1; i <= n; ++i) { scanf ("%d", &l); for (int j = 1; j <= l; ++j) { scanf ("%d", &s[j]); } cout << get_str () << endl; }}