【模板】后缀自动机
后缀自动机是一个能够接受母串所有后缀的最简自动机。
其中,每个节点代表一个字符串集合,该集合中所有的字符串均有相同的 \(right\) 集合。
各个节点之间根据 \(right\) 集合的关系可以组织成一棵树形结构,称为 \(parent\) 树。
后缀自动机最多有 \(2*n - 1\) 个节点。
代码如下
#include <bits/stdc++.h>
using namespace std;
struct SAM {
struct state {
int len, p, cnt;
map<char, int> go;
state(int _len = 0, int _p = -1, int _cnt = 0) {
len = _len;
p = _p;
cnt = _cnt;
}
};
int last;
vector<state> t;
SAM() {
last = 0;
t.push_back({});
}
inline state& operator[](int x) {
return t[x];
}
inline int size() {
return t.size();
}
inline void extend(char c) {
int cur = t.size();
t.push_back({t[last].len + 1, -1, 1});
int x = last;
while (x != -1 && t[x].go.count(c) == 0) {
t[x].go[c] = cur;
x = t[x].p;
}
if (x == -1) {
t[cur].p = 0;
} else {
int y = t[x].go[c];
if (t[y].len == t[x].len + 1) {
t[cur].p = y;
} else {
int z = t.size();
t.push_back(t[y]);
t[z].len = t[x].len + 1;
t[z].cnt = 0;
while (x != -1 && t[x].go[c] == y) {
t[x].go[c] = z;
x = t[x].p;
}
t[cur].p = t[y].p = z;
}
}
last = cur;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
string s;
cin >> s;
n = s.size();
SAM sam;
for (int i = 0; i < n; i++) {
sam.extend(s[i]);
}
vector<vector<int>> adj(sam.size());
for (int i = sam.size() - 1; i >= 1; i--) {
adj[sam[i].p].push_back(i);
}
long long ans = 0;
function<void(int)> dfs = [&](int u) {
for (auto v : adj[u]) {
dfs(v);
sam[u].cnt += sam[v].cnt;
}
if (sam[u].cnt > 1) {
ans = max(ans, (long long)sam[u].cnt * sam[u].len);
}
};
dfs(0);
cout << ans << endl;
return 0;
}