/
suffix_automaton.hpp
81 lines (73 loc) · 2.05 KB
/
suffix_automaton.hpp
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "graph/base.hpp"
template <int sigma = 26>
struct Suffix_Automaton {
struct Node {
array<int, sigma> next; // automaton の遷移先
int link; // suffix link
int size; // node が受理する最長文字列の長さ
Node(int link, int size) : link(link), size(size) { fill(all(next), -1); }
};
vc<Node> nodes;
int last; // 文字列全体を入れたときの行き先
Suffix_Automaton() {
nodes.eb(Node(-1, 0));
last = 0;
}
void add(char c0, char off) {
int c = c0 - 'a';
int new_node = len(nodes);
nodes.eb(Node(-1, nodes[last].size + 1));
int p = last;
while (p != -1 && nodes[p].next[c] == -1) {
nodes[p].next[c] = new_node;
p = nodes[p].link;
}
int q = (p == -1 ? 0 : nodes[p].next[c]);
if (p == -1 || nodes[p].size + 1 == nodes[q].size) {
nodes[new_node].link = q;
} else {
int new_q = len(nodes);
nodes.eb(Node(nodes[q].link, nodes[p].size + 1));
nodes.back().next = nodes[q].next;
nodes[q].link = new_q;
nodes[new_node].link = new_q;
while (p != -1 && nodes[p].next[c] == q) {
nodes[p].next[c] = new_q;
p = nodes[p].link;
}
}
last = new_node;
}
Graph<int, 1> calc_DAG() {
int n = len(nodes);
Graph<int, 1> G(n);
FOR(v, n) {
for (auto&& to: nodes[v].next)
if (to != -1) { G.add(v, to); }
}
G.build();
return G;
}
Graph<int, 1> calc_tree() {
int n = len(nodes);
Graph<int, 1> G(n);
FOR(v, 1, n) {
int p = nodes[v].link;
G.add(p, v);
}
G.build();
return G;
}
int count_substring_at(int p) {
// あるノードについて、最短と最長の文字列長が分かればよい。
// 最長は size が持っている
// 最短は、suffix link 先の最長に 1 を加えたものである。
if (p == 0) return 0;
return nodes[p].size - nodes[nodes[p].link].size;
}
ll count_substring() {
ll ANS = 0;
FOR(i, len(nodes)) ANS += count_substring_at(i);
return ANS;
}
};