BZOJ3172: [Tjoi2013]单词
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
对串建立AC自动机,则一个前缀在文章中出现的次数就是其fail树的子树大小。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=1000010; int ch[maxn][26],pos[maxn],sz[maxn],cnt; void insert(char* s,int k) { int j=0,c; for(int i=0;s[i];i++) { c=s[i]-'a'; if(!ch[j][c]) ch[j][c]=++cnt; sz[j=ch[j][c]]++; } pos[k]=j; } int f[maxn],Q[maxn],first[maxn],next[maxn],to[maxn],e; void AddEdge(int u,int v) { to[++e]=v;next[e]=first[u];first[u]=e; } void dfs(int x) { ren dfs(to[i]),sz[x]+=sz[to[i]]; } void getfail() { int l=0,r=0; rep(c,0,25) if(ch[0][c]) Q[r++]=ch[0][c]; while(l!=r) { int u=Q[l++],v; rep(c,0,25) if(v=ch[u][c]) { int j=f[u];Q[r++]=v; while(j&&!ch[j][c]) j=f[j]; f[v]=ch[j][c]; } } rep(i,1,cnt) AddEdge(f[i],i); dfs(0); } char s[maxn]; int main() { int n=read(); rep(i,1,n) scanf("%s",s),insert(s,i); getfail(); rep(i,1,n) printf("%d\n",sz[pos[i]]); return 0; }