BZOJ3172: [Tjoi2013]单词

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

题解Here!
本来是想找后缀数组的,然后找到了一道$AC$自动机的裸题。。。

把所有单词扔到$AC$自动机里。 当$insert$的时候记录这条路径上的所有点$val++$。

设$p$的$fail$指针指向$q$。

因为根到$p$的路径的某一后缀等同于根到$q$,所以$p$节点为$q$节点贡献的答案是$val[p]$。

具体操作就是记录$buildtree$时的队列,逆序处理为其的$fail$指针贡献答案。

有点像拓扑排序。。。

因为在队列里的节点的深度是单调不下降的,所以这么做是对的。

 附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 1000010
#define MAXM 210
using namespace std;
int n,m=0,size=0;
int id[MAXM],num[MAXN];
char ch[MAXN];
struct AC{
    int fail,val,son[26];
    AC(){
        fail=val=0;
        memset(son,0,sizeof(son));
    }
}a[MAXN];
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
inline int idx(char x){return x-'a';}
int insert(char *s){
    int u=0,l=strlen(s);
    for(int i=0;i<l;i++){
        int c=idx(s[i]);
        if(!a[u].son[c])a[u].son[c]=++size;
        u=a[u].son[c];
        a[u].val++;
    }
    return u;
}
void buildtree(){
    int u,v;
    queue<int> q;
    num[++m]=0;
    for(int i=0;i<26;i++)
    if(a[0].son[i]){
        a[a[0].son[i]].fail=0;
        q.push(a[0].son[i]);
    }
    while(!q.empty()){
        u=q.front();
        q.pop();
        num[++m]=u;
        for(int i=0;i<26;i++){
            if(a[u].son[i]){
                a[a[u].son[i]].fail=a[a[u].fail].son[i];
                q.push(a[u].son[i]);
            }
            else a[u].son[i]=a[a[u].fail].son[i];
        }
    }
}
void query(){
    for(int i=m;i>=1;i--)a[a[num[i]].fail].val+=a[num[i]].val;
}
void work(){
    query();
    for(int i=1;i<=n;i++)printf("%d\n",a[id[i]].val);
}
void init(){
    n=read();
    for(int i=1;i<=n;i++){
        scanf("%s",ch);
        id[i]=insert(ch);
    }
    buildtree();
}
int main(){
    init();
    work();
    return 0;
}

 

posted @ 2018-08-08 20:08  符拉迪沃斯托克  阅读(142)  评论(0编辑  收藏  举报
Live2D