BZOJ3172 - AC automaton + fail tree

Description

Someone reads a dissertation, and a dissertation is made up of many words. But he found that a word appears many times in the paper, and now wants to know how many times each word appears in the paper.

Input

The first integer N indicates how many words there are, and the next N lines have one word per line. Each word consists of lowercase letters, N<=200, and the word length does not exceed 10^6

Output

Output N integers, and the number in the i-th line represents how many times the i-th word appears in the article.

Sample Input

3

a

aa

aaa
Sample Output

6

3

1


This problem requires us to find the number of occurrences of each string in the Trie composed of all strings. If we match one by one, it will definitely time out, so we have to use a better method. Here, you need to use the fail of each node to build a tree, which is called a fail tree.
If we connect the point x to its fail every time, then the resulting tree will have a very magical feature, that is, the substring from the root to the point fail[x] must be the suffix of the substring from the root to x. So that is to say, if we want to count the number of occurrences of the string s in all strings, we only need to find it in its subtree on the fail tree. The specific search method is as follows: we adopt the method from the leaf node to the root, start from the bottom leaf node, add sz[fail[x]] to sz[x], and keep updating, we can find Answer. Because the update is cumulative, it can be guaranteed to increase upward, and because fail[x] is jumped upward every time, it can be guaranteed that the suffix of the current string is jumped to, and the answer can continue to be accumulated, thus ensuring correctness.

Code:

#include<bits/stdc++.h>
using namespace std;
int read(){
    char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int n,cnt,bel[1500000],q[1500000];
string s;
struct node{
    int fail,sz,next[26];
}F[1500000];
void build(string s,int num){
    int pl=0;
    for(int i=0;i<s.length();i++){
        if(F[pl].next[s[i]-'a']) pl=F[pl].next[s[i]-'a'];
        else{
            cnt++;F[pl].next[s[i]-'a']=cnt;pl=cnt;
        }
        F[pl].sz++;
    }
    bel[num]=pl;
}
void fail(){
    int h=0,t=0;
    for(int i=0;i<26;i++) if(F[0].next[i]) F[q[++t]=F[0].next[i]].fail=0;
    while(h<t){
        int now=q[++h];
        for(int i=0;i<26;i++)
         if(F[now].next[i]) F[q[++t]=F[now].next[i]].fail=F[F[now].fail].next[i];
         else F[now].next[i]=F[F[now].fail].next[i];
    }
}
void match(){
    for(int i=cnt;i>=0;i--) F[F[q[i]].fail].sz+=F[q[i]].sz;
    for(int i=1;i<=n;i++) printf("%d\n",F[bel[i]].sz);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        cin>>s;build(s,i);
    }
    fail();
    match();
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325614629&siteId=291194637