260 字
1 分钟
BZOJ 3172 [Tjoi2013]单词 fail tree
Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
Sample Output
6
3
1
题解
fail 树 照着打个板子
#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std;char S[1000005];int Index;struct Trie{ Trie *ch[26]; Trie *fail; int id,num; Trie(){memset(ch,0,sizeof(ch));fail=NULL;fail=0;num=0;id=++Index;}}*root,*word[220];void insert(char *s,int x){ int len=strlen(s); Trie *now=root; for(int i=0;i<len;i++){ if(!now->ch[s[i]-'a'])now->ch[s[i]-'a']=new Trie(); now=now->ch[s[i]-'a']; now->num++; } word[x]=now;}struct edge{ Trie *END;edge *next;}*first[26000500];void add(Trie *a,Trie *b){ edge *k=new edge; k->END=b; k->next=first[a->id]; first[a->id]=k;}void get_fail(){ queue<Trie*> Q; Trie *now=root,*temp; Q.push(now); while(!Q.empty()){ temp=Q.front();Q.pop(); for(int i=0;i<26;i++){ if(temp->ch[i]){ if(temp==root){ temp->ch[i]->fail=root; add(root,temp->ch[i]); } else{ now=temp->fail; while(now&&now->ch[i]==NULL) now=now->fail; if(now==NULL)add(root,temp->ch[i]),temp->ch[i]->fail=root; else add(now->ch[i],temp->ch[i]),temp->ch[i]->fail=now->ch[i]; } Q.push(temp->ch[i]); } } }}void dfs(Trie *rt){ for(edge *now=first[rt->id];now;now=now->next){ dfs(now->END); rt->num+=now->END->num; }}int main(){ int n; root=new Trie(); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",S); insert(S,i); } get_fail(); dfs(root); for(int i=1;i<=n;i++){ printf("%d\n",word[i]->num); }}
BZOJ 3172 [Tjoi2013]单词 fail tree
https://www.nekomio.com/posts/13/