BZOJ3172: [Tjoi2013]单词

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
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;
}
View Code

 

posted @ 2016-03-16 17:06  wzj_is_a_juruo  阅读(141)  评论(0编辑  收藏  举报