forked from ShahjalalShohag/code-library
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Suffix Automaton.cpp
105 lines (101 loc) · 3.09 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
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 9;
// len -> largest string length of the corresponding endpos-equivalent class
// link -> longest suffix that is another endpos-equivalent class.
// firstpos -> 1 indexed end position of the first occurrence of the largest string of that node
// minlen(v) -> smallest string of node v = len(link(v)) + 1
// terminal nodes -> store the suffixes
struct SuffixAutomaton {
struct node {
int len, link, firstpos;
map<char, int> nxt;
};
int sz, last;
vector<node> t;
vector<int> terminal;
vector<long long> dp;
vector<vector<int>> g;
SuffixAutomaton() {}
SuffixAutomaton(int n) {
t.resize(2 * n); terminal.resize(2 * n, 0);
dp.resize(2 * n, -1); sz = 1; last = 0;
g.resize(2 * n);
t[0].len = 0; t[0].link = -1; t[0].firstpos = 0;
}
void extend(char c) {
int p = last;
if (t[p].nxt.count(c)) {
int q = t[p].nxt[c];
if (t[q].len == t[p].len + 1) {
last = q;
return;
}
int clone = sz++;
t[clone] = t[q];
t[clone].len = t[p].len + 1;
t[q].link = clone;
last = clone;
while (p != -1 && t[p].nxt[c] == q) {
t[p].nxt[c] = clone;
p = t[p].link;
}
return;
}
int cur = sz++;
t[cur].len = t[last].len + 1;
t[cur].firstpos = t[cur].len;
p = last;
while (p != -1 && !t[p].nxt.count(c)) {
t[p].nxt[c] = cur;
p = t[p].link;
}
if (p == -1) t[cur].link = 0;
else {
int q = t[p].nxt[c];
if (t[p].len + 1 == t[q].len) t[cur].link = q;
else {
int clone = sz++;
t[clone] = t[q];
t[clone].len = t[p].len + 1;
while (p != -1 && t[p].nxt[c] == q) {
t[p].nxt[c] = clone;
p = t[p].link;
}
t[q].link = t[cur].link = clone;
}
}
last = cur;
}
void build_tree() {
for (int i = 1; i < sz; i++) g[t[i].link].push_back(i);
}
void build(string &s) {
for (auto x: s) {
extend(x);
terminal[last] = 1;
}
build_tree();
}
long long cnt(int i) { //number of times i-th node occurs in the string
if (dp[i] != -1) return dp[i];
long long ret = terminal[i];
for (auto &x: g[i]) ret += cnt(x);
return dp[i] = ret;
}
};
int32_t main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t; cin >> t;
while (t--) {
string s; cin >> s;
int n = s.size();
SuffixAutomaton sa(n);
sa.build(s);
long long ans = 0; //number of unique substrings
for (int i = 1; i < sa.sz; i++) ans += sa.t[i].len - sa.t[sa.t[i].link].len;
cout << ans << '\n';
}
return 0;
}