[洛谷P4081][USACO17DEC]Standing Out from the Herd

题目大意:给你$n$个字符串,对每个字符串求出只在这个字符串中出现的字串的个数

解:先建广义$SAM$,然后对每个点统计一下它的子树中是不是都是在同一个字符串中的,是的话,就把这个点标成这一个字符串,计算贡献

卡点:

C++ Code:

#include <algorithm>
#include <cstdio>
#include <cstring>
#define maxn 100010

long long ans[maxn];
namespace SAM {
#define N (maxn << 1)
	int R[N], fail[N], nxt[N][26];
	int lst = 1, idx = 1, bel[N];

	void append(int ch, int tg) {
		int p = lst, np = lst = ++idx; R[np] = R[p] + 1, bel[np] = tg;
		for (; p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = np;
		if (!p) fail[np] = 1;
		else {
			int q = nxt[p][ch];
			if (R[p] + 1 == R[q]) fail[np] = q;
			else {
				int nq = ++idx;
				fail[nq] = fail[q], R[nq] = R[p] + 1, fail[q] = fail[np] = nq;
				std::copy(nxt[q], nxt[q] + 26, nxt[nq]);
				for (; p && nxt[p][ch] == q; p = fail[p]) nxt[p][ch] = nq;
			}
		}
	}

	int head[N], cnt;
	struct Edge {
		int to, nxt;
	} e[N];
	inline void addedge(int a, int b) {
		e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
	}
	void dfs(int u) {
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			dfs(v);
			if (~bel[v]) {
				if (!bel[u]) bel[u] = bel[v];
				else if (bel[u] != bel[v]) bel[u] = -1;
			} else bel[u] = -1;
		}
	}
	void work() {
		for (int i = 2; i <= idx; i++) addedge(fail[i], i);
		dfs(1);
		for (int i = 2; i <= idx; i++) if (bel[i] != -1) ans[bel[i]] += R[i] - R[fail[i]];
	}
#undef N
}

int n;
char s[maxn];
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%s", s);
		SAM::lst = 1;
		for (register char *ch = s; *ch; ++ch) SAM::append(*ch - 'a', i);
	}
	SAM::work();
	for (int i = 1; i <= n; i++) printf("%lld\n", ans[i]);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10163850.html