Repository navigation
Expand file tree
/
Copy pathSuffix-Tree (Ukkonen's Algorithm).cpp
More file actions
94 lines (89 loc) · 2.82 KB
/
Copy pathSuffix-Tree (Ukkonen's Algorithm).cpp
File metadata and controls
94 lines (89 loc) · 2.82 KB
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
/**
* Author: Unknown
* Date: 2017-05-15
* Source: https://e-maxx.ru/algo/ukkonen
* Description: Ukkonen's algorithm for online suffix tree construction.
* Each node contains indices [l, r) into the string, and a list of child
* nodes. Suffixes are given by traversals of this tree, joining [l, r)
* substrings. The root is 0 (has l = -1, r = 0), non-existent children are -1.
* To get a complete tree, append a dummy symbol -- otherwise it may contain
* an incomplete path (still useful for substring matching, though).
* Time: $O(26N)$
* Status: stress-tested a bit
*/
#pragma once
#include "../Contest/template.cpp"
struct SuffixTree {
enum { N = 200010, ALPHA = 26 }; // N ~ 2*maxlen+10
int toi(char c) { return c - 'a'; }
string a; // v = cur node, q = cur position
int t[N][ALPHA], l[N], r[N], p[N], s[N], v = 0, q = 0, m = 2;
void ukkadd(int i, int c) {
suff:
if (r[v] <= q) {
if (t[v][c] == -1) {
t[v][c] = m;
l[m] = i;
p[m++] = v;
v = s[v];
q = r[v];
goto suff;
}
v = t[v][c];
q = l[v];
}
if (q == -1 || c == toi(a[q]))
q++;
else {
l[m + 1] = i;
p[m + 1] = m;
l[m] = l[v];
r[m] = q;
p[m] = p[v];
t[m][c] = m + 1;
t[m][toi(a[q])] = v;
l[v] = q;
p[v] = m;
t[p[m]][toi(a[l[m]])] = m;
v = s[p[m]];
q = l[m];
while (q < r[m]) {
v = t[v][toi(a[q])];
q += r[v] - l[v];
}
if (q == r[m])
s[m] = v;
else
s[m] = m + 2;
q = r[v] - (q - r[m]);
m += 2;
goto suff;
}
}
SuffixTree(string a) : a(a) {
fill(r, r + N, len(a));
memset(s, 0, sizeof s);
memset(t, -1, sizeof t);
fill(t[1], t[1] + ALPHA, 0);
s[0] = 1;
l[0] = l[1] = -1;
r[0] = r[1] = p[0] = p[1] = 0;
rep(i, 0, len(a)) ukkadd(i, toi(a[i]));
}
// example: find longest common substring (uses ALPHA = 28)
pii best;
int lcs(int node, int i1, int i2, int olen) {
if (l[node] <= i1 && i1 < r[node]) return 1;
if (l[node] <= i2 && i2 < r[node]) return 2;
int mask = 0, len = node ? olen + (r[node] - l[node]) : 0;
rep(c, 0, ALPHA) if (t[node][c] != -1) mask |=
lcs(t[node][c], i1, i2, len);
if (mask == 3) best = max(best, {len, r[node] - len});
return mask;
}
static pii LCS(string s, string t) {
SuffixTree st(s + (char)('z' + 1) + t + (char)('z' + 2));
st.lcs(0, len(s), len(s) + 1 + len(t), 0);
return st.best;
}
};