P4081 [USACO17DEC]Standing Out from the Herd P [广义SAM]

一世执手 提交于 2020-03-25 20:18:47

我们直接把重复的部分去掉。

\(\sum len_i - len_{fa_i}\)

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 62;
char s[maxn], str[maxn];
int tot = 0 ;
long long Ans[maxn] ;

struct SAM {
	int ch[maxn][26], cnt, len[maxn], fa[maxn];

	SAM() {
		cnt = 1;
	}

	int ins(int c, int las) {
		int p = las, np = ++cnt;
		len[np] = len[p] + 1;
		for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
		if (!p) {
			fa[np] = 1;
		} else {
			int q = ch[p][c];
			if (len[q] == len[p] + 1) {
				fa[np] = q;
			} else {
				int nq = ++cnt;
				memcpy(ch[nq], ch[q], sizeof(ch[q]));
				fa[nq] = fa[q], fa[q] = fa[np] = nq, len[nq] = len[p] + 1;
				for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
			}
		}
		return np;
	}
	
	int id[maxn] ;
	
	void col(int x , int c) {
		for( ; x && id[x] ^ c && ~ id[x] ; x = fa[x])
			id[x] = (id[x]) ? -1 : c ;
	}
	
	void calc() {
		int c = 1 , p = 1 ;
		for(int i = 1 ; i <= tot ; i ++) {
			if(! isspace(str[i])) {
				col(p = ch[p][str[i] - 'a'] , c) ;
			}
			else {
				p = 1 , ++ c ;
			}
		}
		for(int i = 1 ; i <= cnt ; i ++) {
			if(~ id[i]) {
				Ans[id[i]] += len[i] - len[fa[i]] ;
			}
		}
	}
} sam;

struct Trie {
	int ch[maxn][26], cnt, qwq[maxn], fa[maxn];

	Trie() {
		cnt = 1;
	}

	void ins(int len) {
		int p = 1;
		for (int i = 1; i <= len; i++) {
			int c = s[i] - 'a';
			if (!ch[p][c]) ch[p][c] = ++cnt, qwq[cnt] = c, fa[cnt] = p;
			p = ch[p][c];
		}
	}

	int pos[maxn];

	void buildsam() {
		queue<int> q;
		for (int i = 0; i < 26; i++)
			if (ch[1][i]) q.push(ch[1][i]);
		pos[1] = 1;
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			pos[u] = sam.ins(qwq[u], pos[fa[u]]);
			for (int i = 0; i < 26; i++)
				if (ch[u][i]) q.push(ch[u][i]);
		}
	}
} trie;

void cpy(int len) {
	for(int i = 1 ; i <= len ; i ++) str[++ tot] = s[i] ;
	str[++ tot] = '\n' ;
}

int main() {
	int _;
	scanf("%d", &_);
	for(int i = 1 ; i <= _ ; i ++) scanf("%s", s + 1), trie.ins(strlen(s + 1)), cpy(strlen(s + 1));
	trie.buildsam(), sam.calc();
	for(int i = 1 ; i <= _ ; i ++) printf("%lld\n" , Ans[i]) ;
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!