【模板】后缀自动机

后缀自动机是一个能够接受母串所有后缀的最简自动机。
其中,每个节点代表一个字符串集合,该集合中所有的字符串均有相同的 \(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;
} 
posted @ 2019-09-25 18:17  shellpicker  阅读(160)  评论(0编辑  收藏  举报