后缀自动机再复习 + [USACO17DEC] Standing Out from the Herd

here:https://oi-wiki.org/string/sam/

下面转自 KesdiaelKen的雷蒻论坛

来个广义后缀自动机模板题 [USACO17DEC]Standing Out from the Herd

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int n, l[MAXN], m, s[MAXN];
long long ans[MAXN];
namespace SAM {
	const int MAXP = 200005;
	const int C = 26;
	int tr[MAXP][C], link[MAXP] = { -1 }, len[MAXP], sz = 1, last;
	int vis[MAXP];
	inline void Insert(int c) {
		int cur = sz++, p;
		len[cur] = len[last] + 1;
		for(p = last; ~p && !tr[p][c]; p = link[p]) tr[p][c] = cur;
		if(!~p) link[cur] = 0;
		else {
			int q = tr[p][c];
			if(len[q] == len[p] + 1) link[cur] = q;
			else {
				int clone = sz++;
				len[clone] = len[p] + 1, link[clone] = link[q];
				memcpy(tr[clone], tr[q], sizeof tr[q]);
				for(; ~p && tr[p][c] == q; p = link[p]) tr[p][c] = clone;
				link[q] = link[cur] = clone;
			}
		}
		last = cur;
	}
	inline void Update(int x, int i) {
		for(; ~x && vis[x] != i && ~vis[x]; x = link[x])
			if(vis[x]) vis[x] = -1;
			else vis[x] = i;
	}
	inline void Solve() {
		m = 0;
		for(int i = 1; i <= n; ++i)
			for(int j = 0, r = 0; j < l[i]; ++j)
				Update(r = tr[r][s[m++]], i);
		for(int i = 1; i < sz; ++i)
			if(~vis[i]) ans[vis[i]] += len[i] - len[link[i]];
		for(int i = 1; i <= n; ++i)
			printf("%lld\n", ans[i]);
	}
}
using namespace SAM;
int main () {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		char ch; last = 0;
		while(!isalpha(ch=getchar()));
		while(isalpha(ch))
			++l[i], Insert(s[m++] = ch-'a'), ch = getchar();
	}
	Solve();
}
posted @ 2019-12-14 14:50  _Ark  阅读(80)  评论(0编辑  收藏  举报