BZOJ 3172: [Tjoi2013]单词
3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3439 Solved: 1650
[Submit][Status][Discuss]
Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
a
aa
aaa
Sample Output
6
3
1
3
1
HINT
Source
分析:
我们对于每一个节点维护其子树fail指针和...就是答案...
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=200+5,maxm=1000000+5;
int n,tot,head,tail,q[maxm],pos[maxn];
char s[maxm];
struct trie{
int sum,fail,nxt[26];
}tr[maxm];
inline void insert(int &x){
scanf("%s",s);int p=0,len=strlen(s);
for(int i=0;i<len;i++){
if(!tr[p].nxt[s[i]-'a'])
tr[p].nxt[s[i]-'a']=++tot,tr[tot].fail=-1;
p=tr[p].nxt[s[i]-'a'],tr[p].sum++;
}
x=p;
}
inline void buildACM(void){
head=0,tail=0;q[0]=0;
while(head<=tail){
int id=q[head++],p=-1;
for(int i=0;i<26;i++)
if(tr[id].nxt[i]){
if(id){
p=tr[id].fail;
while(p!=-1){
if(tr[p].nxt[i]){
tr[tr[id].nxt[i]].fail=tr[p].nxt[i];
break;
}
p=tr[p].fail;
}
if(p==-1) tr[tr[id].nxt[i]].fail=0;
}
else
tr[tr[id].nxt[i]].fail=0;
q[++tail]=tr[id].nxt[i];
}
}
for(int i=tail;i>=0;i--)
tr[tr[q[i]].fail].sum+=tr[q[i]].sum;
}
signed main(void){
scanf("%d",&n);tr[0].fail=-1;
for(int i=1;i<=n;i++)
insert(pos[i]);
buildACM();
for(int i=1;i<=n;i++)
printf("%d\n",tr[pos[i]].sum);
return 0;
}
By NeighThorn

浙公网安备 33010602011771号