首页 > 代码库 > [bzoj3172][Tjoi2013]单词

[bzoj3172][Tjoi2013]单词

Description

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

Input

第一个一个整数N,表示有多少个单词.

接下来N行每行一个单词,每个单词由小写字母组成.

Output

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

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

HINT

N$\leq$200,单词总长度不超过$10^6$

Solution

AC自动机+fail树.

fail树中求子树和即可.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define M 26
#define K 205
#define N 1000005
using namespace std;
struct trie{
    int chl[M],nxt,cnt;
}t[N];
struct graph{
    int nxt,to;
}e[N];
int a[K],g[N],tot[N],n,m,cnt;
char c[N];
queue<int> q;
inline void addedge(int x,int y){
    e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
} 
inline int insert(int u,int i){
    ++t[u].cnt;
    if(i==m) return u;
    int k=c[i]-a;
    if(!t[u].chl[k])
        t[u].chl[k]=++cnt;
    return insert(t[u].chl[k],i+1);
}
inline void get_nxt(){
    for(int i=0;i<M;++i)
        if(t[0].chl[i])
            q.push(t[0].chl[i]);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0,j,c;i<26;++i)
            if(c=t[u].chl[i]){
                q.push(c);j=t[u].nxt;
                while(j&&!t[j].chl[i])
                    j=t[j].nxt;
                t[c].nxt=t[j].chl[i];
            }
    }
}
inline void ask(int u){
    tot[u]=t[u].cnt;
    for(int i=g[u];i;i=e[i].nxt){
        ask(e[i].to);tot[u]+=tot[e[i].to];
    }
}
inline void Aireen(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%s",c);
        m=strlen(c);
        a[i]=insert(0,0);
    }
    get_nxt();m=cnt;cnt=0;
    for(int i=1;i<=m;++i)
        addedge(t[i].nxt,i);
    ask(0);
    for(int i=1;i<=n;++i)
        printf("%d\n",tot[a[i]]);
}
int main(){
    freopen("word.in","r",stdin);
    freopen("word.out","w",stdout);
    Aireen();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

[bzoj3172][Tjoi2013]单词