[BZOJ3172][Tjoi2013]单词

[Tjoi2013]单词

Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
Sample Output
6
3
1

Solution:
首先我们构建出fail树。
由fail树的性质我们知道,对于fail树上的某一个结点p,都代表了trie里的一个串s,而这个结点的子树中的所有结点代表的字符串s’,都以该结点代表的字符串s为后缀。
因此,我们在建立trie的时候可以统计出每一个结点p代表的字符串s作为后缀出现了几次(只要在建trie的时候路过这个点就++这个点的cnt),再加上该结点在fail树中的子树里所有点的cnt就是答案了。

#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define REP(i, n) for (int i = 0; i < n; i++)
#define fst first
#define sec second
#define MS(_) memset(_, 0, sizeof(_))
#define PB push_back
#define MP make

template<typename _T> inline void read(_T &x){
    x = 0; bool f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = 0; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    x = f ? x : -x;
}

const int N = 222;
const int L = 1111111;
struct Node{
    Node *fail, *nxt[26]; int cnt;
}pool[L<<1], *root, *tail = pool;
char st[L];
int q[L], pos[L], n, tot;
inline void ins(Node *&rt, char *p, int no){
    if (!rt) rt = tail++;
    rt->cnt++;
    if (!*p) pos[no] = (int)rt;
    else ins(rt->nxt[*p-'a'], p+1, no);
}
inline void build(){ int l, r;
    root->fail = root;
    for (q[l = r = 1] = (int)root; l <= r; l++){
        Node *p = (Node *)q[l];
        REP(i, 26) if (p->nxt[i]) q[++r] = (int)p->nxt[i], p->nxt[i]->fail = p == root ? root : p->fail->nxt[i];
                   else p->nxt[i] = p == root ? root : p->fail->nxt[i];
    }
    tot = r;
}
inline void dp(){
     per(i, tot, 1){ Node *p = (Node *)q[i]; p->fail->cnt += p->cnt; } 
}

int main(){
    read(n);

    rep(i, 1, n) scanf("%s", st), ins(root, st, i);
    build();
    dp();
    rep(i, 1, n){ Node *p = (Node *)pos[i]; printf("%d\n", p->cnt); }

    return 0;    
}

你可能感兴趣的:(AC自动机,fail树)