洛谷 - P3966 - 单词 - AC自动机

https://www.luogu.org/problemnew/show/P3966
因为文本串就是字典本身,所以这个和平时的AC自动机不太一样。平时的query要沿着fail树把子树的出现次数依次统计。但是这个的query就是对每个字典里的字符串搞一次。所以就直接按广搜的顺序反过来树形dp统计出子树中的出现次数,直接回答。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e6;
const int MAXM = 2e2;

int idx[MAXM + 5];

struct Trie {
    int trie[MAXN + 5][26], fail[MAXN + 5], cnt[MAXN + 5], que[MAXN + 5];
    int root, top;
    int newnode() {
        for(int i = 0; i < 26; i++)
            trie[top][i] = -1;
        cnt[top++] = 0;
        return top - 1;
    }

    void init() {
        top = 0;
        root = newnode();
    }

    void insert(char buf[], int id) {
        int len = strlen(buf);
        int cur = root;
        for(int i = 0; i < len; i++) {
            int u = buf[i] - 'a';
            if(trie[cur][u] == -1)
                trie[cur][u] = newnode();
            cur = trie[cur][u];
            cnt[cur]++;
        }
        idx[id] = cur;
    }

    void build() {
        int head = 0, tail = 0;
        fail[root] = root;
        for(int i = 0; i < 26; i++) {
            if(trie[root][i] == -1)
                trie[root][i] = root;
            else {
                fail[trie[root][i]] = root;
                que[tail++] = trie[root][i];
            }
        }
        while(head < tail) {
            int cur = que[head++];
            for(int i = 0; i < 26; i++) {
                if(trie[cur][i] == -1)
                    trie[cur][i] = trie[fail[cur]][i];
                else {
                    fail[trie[cur][i]] = trie[fail[cur]][i];
                    que[tail++] = trie[cur][i];
                }
            }
        }
        for(int i = tail - 1; i >= 0; i--) {
            cnt[fail[que[i]]] += cnt[que[i]];
        }
    }
};

char buf[MAXN + 5];

Trie ac;

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    int n;
    scanf("%d", &n);
    ac.init();
    for(int i = 0; i < n; i++) {
        scanf("%s", buf);
        ac.insert(buf, i);
    }
    ac.build();
    for(int i = 0; i < n; i++)
        printf("%d\n", ac.cnt[idx[i]]);
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/11084288.html