-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSuffix automaton.cpp
142 lines (130 loc) · 3.25 KB
/
Suffix automaton.cpp
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
struct state {
int len, link, cnt, firstpos;
// this can be optimized using a vector with the
// alphabet size
map<char, int> next;
vi inv_link;
};
struct SuffixAutomaton {
vector<state> st;
int sz = 0;
int last;
vc cloned;
SuffixAutomaton(const string &s, int maxlen)
: st(maxlen * 2), cloned(maxlen * 2) {
st[0].len = 0;
st[0].link = -1;
sz++;
last = 0;
for (auto &c : s) add_char(c);
// precompute for count occurences
for (int i = 1; i < sz; i++) {
st[i].cnt = !cloned[i];
}
vector<pair<state, int>> aux;
for (int i = 0; i < sz; i++) {
aux.push_back({st[i], i});
}
sort(all(aux), [](const pair<state, int> &a,
const pair<state, int> &b) {
return a.fst.len > b.fst.len;
});
for (auto &[stt, id] : aux) {
if (stt.link != -1) {
st[stt.link].cnt += st[id].cnt;
}
}
// for find every occurende position
for (int v = 1; v < sz; v++) {
st[st[v].link].inv_link.push_back(v);
}
}
void add_char(char c) {
int cur = sz++;
st[cur].len = st[last].len + 1;
st[cur].firstpos = st[cur].len - 1;
int p = last;
// follow the suffix link until find a
// transition to c
while (p != -1 and !st[p].next.count(c)) {
st[p].next[c] = cur;
p = st[p].link;
}
// there was no transition to c so create and
// leave
if (p == -1) {
st[cur].link = 0;
last = cur;
return;
}
int q = st[p].next[c];
if (st[p].len + 1 == st[q].len) {
st[cur].link = q;
} else {
int clone = sz++;
cloned[clone] = true;
st[clone].len = st[p].len + 1;
st[clone].next = st[q].next;
st[clone].link = st[q].link;
st[clone].firstpos = st[q].firstpos;
while (p != -1 and st[p].next[c] == q) {
st[p].next[c] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
last = cur;
}
bool checkOccurrence(
const string &t) { // O(len(t))
int cur = 0;
for (auto &c : t) {
if (!st[cur].next.count(c)) return false;
cur = st[cur].next[c];
}
return true;
}
ll totalSubstrings() { // distinct, O(len(s))
ll tot = 0;
for (int i = 1; i < sz; i++) {
tot += st[i].len - st[st[i].link].len;
}
return tot;
}
// count occurences of a given string t
int countOccurences(const string &t) {
int cur = 0;
for (auto &c : t) {
if (!st[cur].next.count(c)) return 0;
cur = st[cur].next[c];
}
return st[cur].cnt;
}
// find the first index where t appears a
// substring O(len(t))
int firstOccurence(const string &t) {
int cur = 0;
for (auto c : t) {
if (!st[cur].next.count(c)) return -1;
cur = st[cur].next[c];
}
return st[cur].firstpos - len(t) + 1;
}
vi everyOccurence(const string &t) {
int cur = 0;
for (auto c : t) {
if (!st[cur].next.count(c)) return {};
cur = st[cur].next[c];
}
vi ans;
getEveryOccurence(cur, len(t), ans);
return ans;
}
void getEveryOccurence(int v, int P_length,
vi &ans) {
if (!cloned[v])
ans.pb(st[v].firstpos - P_length + 1);
for (int u : st[v].inv_link)
getEveryOccurence(u, P_length, ans);
}
};