P3966 [TJOI2013]单词(AC自动机,fail树)

Posted H-w-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3966 [TJOI2013]单词(AC自动机,fail树)相关的知识,希望对你有一定的参考价值。

P3966 [TJOI2013]单词

题意:

给出n个字符串,问各个字符串在所有字符串中出现的次数

思路:

对于一个字符串来说,我们对它在trie树上的路径节点++,表示当前节点一共出现多少次。

再建一棵fail树,对于fail树的一个子树来说,子树权值等于根节点所表示的字符串出现的次数。

所以我们就可以dfs去统计每个子树的权值和,在输出每个字符串对应节点的权值,就是答案。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6+10;
int trie[N][30], val[N], tot;
int fail[N];
int head[N], nex[N], to[N], cnt = 0;
int xx[N];
void addE(int x, int y) 
	nex[++cnt] = head[x];
	to[cnt] = y;
	head[x] = cnt;

int insert(char *x) 
	int p = 0, len = strlen(x);
	for(int i=0; i<len; i++) 
		int u = x[i] - 'a';
		if(!trie[p][u]) trie[p][u] = ++tot;
		p = trie[p][u];
		val[p]++;
	
	return p;

int aa;
void bfs() 
	queue<int> q;
	for(int i=0; i<26; i++) 
		if(trie[0][i]) q.push(trie[0][i]);
	
	while(q.size()) 
		int p = q.front(); q.pop();
		xx[++aa] = p;
		for(int i=0; i<26; i++) 
			if(trie[p][i]) fail[trie[p][i]] = trie[fail[p]][i], q.push(trie[p][i]);
			else trie[p][i] = trie[fail[p]][i];
		
	
	for(int i=1; i<=tot; i++) 
		// cout << fail[i] << ' ' << i << endl;
		addE(fail[i], i);
	

void dfs(int x) 
	for(int i=head[x]; i; i=nex[i]) 
		// cout << x << ' ' << to[i] << endl;
		dfs(to[i]);
		val[x] += val[to[i]];
	

char s[N];
int idx[N];
signed main() 
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	int n;
	scanf("%lld", &n);
	for(int i=1; i<=n; i++) 
		scanf("%s", s);
		idx[i] = insert(s);
	
	bfs();
	dfs(0);
	// for(int i=aa; i>=1; i--) 
	// 	val[fail[xx[i]]] += val[xx[i]];
	// 
	for(int i=1; i<=n; i++) 
		printf("%lld\\n", val[idx[i]]);
	
	return 0;

以上是关于P3966 [TJOI2013]单词(AC自动机,fail树)的主要内容,如果未能解决你的问题,请参考以下文章

P3966 [TJOI2013]单词(AC自动机,fail树)

P3966 [TJOI2013]单词

BZOJ 3172: [Tjoi2013]单词 AC自动机

bzoj3172: [Tjoi2013]单词 字符串-AC自动机

BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

3172. [TJOI2013]单词AC自动机