0%

板子 广义SAM

广义后缀自动机,即多串的 SAM。

推荐 辰星凌的博客

设 trie 树大小 \(|T|\),字符集大小 \(|A|\)

\(G(T)\) 表示 \(T\) 的所有叶子深度之和。

在线做法

每次插入新串时,将 \(last\) 重置,并加入特判。

复杂度 \(\mathcal O(|T||A|+G(T))\),常数比离线做法小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct SuffixAutomaton {
int tot;
int ch[N][26], link[N], len[N], pos[N];
SuffixAutomaton() : tot(1) {}
inline int insert(int c, int last) {
if (ch[last][c]) {
int p = last, q = ch[p][c];
if (len[q] == len[p] + 1) return q;
else {
int nq = ++tot;
len[nq] = len[p] + 1, link[nq] = link[q];
memcpy(ch[nq], ch[q], sizeof ch[q]);
link[q] = nq;
while (p && ch[p][c] == q) ch[p][c] = nq, p = link[p];
return nq;
}
}
int p = last, np = ++tot;
len[np] = len[p] + 1;
while (p && !ch[p][c]) ch[p][c] = np, p = link[p];
if (!p) link[np] = 1;
else {
int q = ch[p][c];
if (len[q] == len[p] + 1) link[np] = q;
else {
int nq = ++tot;
len[nq] = len[p] + 1, link[nq] = link[q];
memcpy(ch[nq], ch[q], sizeof ch[q]);
link[q] = link[np] = nq;
while (p && ch[p][c] == q) ch[p][c] = nq, p = link[p];
}
}
return np;
}
} A;

离线做法

先将所有串插到 trie 里,再 bfs 构建。

复杂度 \(\mathcal O(|T||A|+|T|)\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
struct Trie {
int tot;
int ch[N][26], fa[N], val[N];
Trie() : tot(1) {}
inline void insert(char *s) {
int p = 1;
for (int i = 0; s[i]; ++i) {
int c = s[i] - 'a';
if (!ch[p][c]) {
ch[p][c] = ++tot;
val[ch[p][c]] = c, fa[ch[p][c]] = p;
}
p = ch[p][c];
}
}
} T;

struct SuffixAutomaton {
int tot;
int ch[N][26], link[N], len[N], pos[N];
queue<int> q;
SuffixAutomaton() : tot(1) {}
inline int insert(int c, int last) {
int p = last, np = ++tot;
len[np] = len[p] + 1;
while (p && !ch[p][c]) ch[p][c] = np, p = link[p];
if (!p) link[np] = 1;
else {
int q = ch[p][c];
if (len[q] == len[p] + 1) link[np] = q;
else {
int nq = ++tot;
len[nq] = len[p] + 1, link[nq] = link[q];
memcpy(ch[nq], ch[q], sizeof ch[q]);
link[q] = link[np] = nq;
while (p && ch[p][c] == q) ch[p][c] = nq, p = link[p];
}
}
return np;
}
inline void build() {
for (int i = 0; i < 26; ++i)
if (T.ch[1][i]) q.push(T.ch[1][i]);
pos[1] = 1;
while (!q.empty()) {
int u = q.front();
q.pop();
pos[u] = insert(T.val[u], pos[T.fa[u]]);
for (int i = 0; i < 26; ++i)
if (T.ch[u][i]) q.push(T.ch[u][i]);
}
}
} A;