用广义SAM写的。特意加了注释。感觉对SAM的感觉又深入了一些。
#include <cstdio>
#include <map>
#define N 100010
using namespace std;
inline char gc() {
static char now[1<<16], *S, *T;
if(S == T) {T = (S = now) + fread(now, 1, 1<<16, stdin); if(S == T) return EOF;}
return *S++;
}
inline int read() {
int x = 0, f = 1; char c = gc();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = gc();}
while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = gc();}
return x * f;
}
int str[N], len1[50010], len2[50010];
int n, m, tot;
struct SAM {
int sz, last, mx[N<<1], fa[N<<1], ans[50010];
map<int, int> nxt[N<<1];
int las[N<<1], siz[N<<1]; //这个节点目前属于哪个模式串(随着i的增大,也应该越来越大),以及这个节点集合共包含于多少个模式串
int marked[N<<1]; //作为终点出现过几次
inline void extend(int c) {
int p = last, np = ++sz;
last = np;
mx[np] = mx[p] + 1;
for(; p && !nxt[p].count(c); p = fa[p]) nxt[p][c] = np;
if(!p) fa[np] = 1;
else {
int q = nxt[p][c];
if(mx[p] + 1 == mx[q]) fa[np] = q;
else {
int nq = ++sz;
mx[nq] = mx[p] + 1;
nxt[nq] = nxt[q];
fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for(; nxt[p][c] == q; p = fa[p]) nxt[p][c] = nq;
}
}
}
inline void update1(int x, int y) {for(; x && las[x] != y; x = fa[x]) {++siz[x]; las[x] = y;}} //用las数组是因为,相同的las只算一次(就比如两个属于同模式串的节点,都能跳到根,但只应该算一次)
inline void update2(int x, int y) {for(; x && las[x] != y; x = fa[x]) {las[x] = y; ans[y]+= marked[x];}} //正常统计,las数组用途同上(这是一个很好的技巧)
inline void build() {
sz = 1; tot = 0;
for(int i = 1; i <= n; ++i) {
len1[i] = read(); last = 1; //广义SAM
for(int j = 1; j <= len1[i]; ++j) {
str[++tot] = read();
extend(str[tot]);
}
len2[i] = read(); last = 1;
for(int j = 1; j <= len2[i]; ++j) {
str[++tot] = read();
extend(str[tot]);
}
}
tot = 0;
for(int i = 1; i <= n; ++i) { //整理每个节点的siz
for(int j = 1, x = 1; j <= len1[i]; ++j) update1(x = nxt[x][str[++tot]], i);
for(int j = 1, x = 1; j <= len2[i]; ++j) update1(x = nxt[x][str[++tot]], i);
}
}
inline void solve() {
while(m--) {
int len = read();
bool flag = 0; int x = 1;
for(int i = 1; i <= len; ++i) {
int d = read();
if(!flag) {
if(nxt[x][d]) x = nxt[x][d];
else flag = 1; //匹配失败了是不能跳fa的,因为要求完美匹配。但依旧不可以break,因为尚未读完。
}
}
if(!flag) ++marked[x], printf("%d\n", siz[x]);
else puts("0");
}
int tot = 0;
for(int i = 1; i <= sz; ++i) las[i] = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 1, x = 1; j <= len1[i]; ++j) update2(x = nxt[x][str[++tot]], i);
for(int j = 1, x = 1; j <= len2[i]; ++j) update2(x = nxt[x][str[++tot]], i);
}
for(int i = 1; i <= n; ++i) printf("%d ", ans[i]);
}
}Sam;
int main() {
n = read(); m = read();
Sam.build(); Sam.solve();
return 0;
}