传送门
题意:某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
思路:
建出
f
a
i
l
fail
fail树然后统计每个节点的
s
i
z
e
size
size即可
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e6+5;
char s[N];
int n;
namespace acam{
int son[N][26],siz[N],tot=1,rt=1,fail[N],val[N],ed[N];
inline void insert(char*s,int len,int id){
int p=rt;
for(ri x,i=1;i<=len;++i){
if(!son[p][x=s[i]-'a'])son[p][x]=++tot;
p=son[p][x];
++val[p];
}
ed[id]=p;
}
inline void getfail(){
static int q[N],hd,tl;
hd=1,tl=0;
for(ri i=0;i<26;++i)if(son[rt][i])fail[q[++tl]=son[rt][i]]=rt;
while(hd<=tl){
int p=q[hd++];
for(ri i=0;i<26;++i){
if(!son[p][i]){son[p][i]=son[fail[p]][i];continue;}
fail[son[p][i]]=max(rt,son[fail[p]][i]),q[++tl]=son[p][i];
}
}
for(ri i=tot;i^1;--i)val[fail[q[i]]]+=val[q[i]];
}
}
int main(){
scanf("%d",&n);
for(ri i=1;i<=n;++i){
scanf("%s",s+1);
acam::insert(s,strlen(s+1),i);
}
acam::getfail();
for(ri i=1;i<=n;++i)cout<<acam::val[acam::ed[i]]<<'\n';
return 0;
}