BZOJ 3172: [Tjoi2013]单词

3172: [Tjoi2013]单词

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 3439  Solved: 1650
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

HINT

 

Source

分析:

我们对于每一个节点维护其子树fail指针和...就是答案...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=200+5,maxm=1000000+5;

int n,tot,head,tail,q[maxm],pos[maxn];

char s[maxm];

struct trie{
    int sum,fail,nxt[26];  
}tr[maxm];

inline void insert(int &x){
    scanf("%s",s);int p=0,len=strlen(s);
    for(int i=0;i<len;i++){
        if(!tr[p].nxt[s[i]-'a'])
            tr[p].nxt[s[i]-'a']=++tot,tr[tot].fail=-1;
        p=tr[p].nxt[s[i]-'a'],tr[p].sum++;
    }
    x=p;
}

inline void buildACM(void){
    head=0,tail=0;q[0]=0;
    while(head<=tail){
        int id=q[head++],p=-1;
        for(int i=0;i<26;i++)
            if(tr[id].nxt[i]){
                if(id){
                    p=tr[id].fail;
                    while(p!=-1){
                        if(tr[p].nxt[i]){
                            tr[tr[id].nxt[i]].fail=tr[p].nxt[i];
                            break;
                        }
                        p=tr[p].fail;
                    }
                    if(p==-1) tr[tr[id].nxt[i]].fail=0;
                }
                else
                    tr[tr[id].nxt[i]].fail=0;
                q[++tail]=tr[id].nxt[i];
            }
    }
    for(int i=tail;i>=0;i--)
        tr[tr[q[i]].fail].sum+=tr[q[i]].sum;
}

signed main(void){
    scanf("%d",&n);tr[0].fail=-1;
    for(int i=1;i<=n;i++)
        insert(pos[i]);
    buildACM();
    for(int i=1;i<=n;i++)
        printf("%d
",tr[pos[i]].sum);
    return 0;
}

  


By NeighThorn

原文地址:https://www.cnblogs.com/neighthorn/p/6402223.html