[Codeforces 1207G] Indie Album

https://codeforces.ml/contest/1207/problem/G

题意:
给你一棵字典树,每次询问给定一个模式串和字典树上的一个前缀串,问模式串在这个前缀串中出现了多少次。

思路:
如果文本串是单串的话,就是 \(AC\) 自动机板子题了。现在把文本串放到了 \(Trie\) 上,但由于都是前缀串,很容易想到将询问离线,用 \(dfs\) 的方式去遍历 \(Trie\) ,然后出来再消去影响就行了。但是自动机上的其他模式串会对当前答案造成影响。我们考虑 \(fail\) 指针的作用,指向最长后缀所在的节点,所以如果在 \(AC\) 自动机上到达了某一模式串,一直反方向跑 \(fail\) 指针,都是合法的,反之都不合法。那么我们根据 \(fail\) 树跑一遍欧拉序,用数据结构维护子树的权值和,就能解决了。

文本串也不用真的建 \(Trie\) ,直接塞到 \(vector\) 里就行,可以减少码量和空间复杂度,好写很多。

好久没写 \(AC\) 自动机了,都快忘光了,赶紧写道复习下,欸嘿。

#include <bits/stdc++.h>

using namespace std;

inline int rd() {
    int f = 0; int x = 0; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
    for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    if (f) x = -x;
    return x;
}

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

const int N = 4e5 + 7;

struct Bit {
    vector<int> bit;
    int n;
    void init(int N) {
        n = N;
        bit.resize(n + 1, 0);
    }
    int lowbit(int x) {
        return x & -x;
    }
    int add(int i, int x) {
        while (i <= n) {
            bit[i] += x;
            i += lowbit(i);
        }
    }

    int query(int i) {
        int res = 0;
        while (i) {
            res += bit[i];
            i -= lowbit(i);
        }
        return res;
    }
}b;

vector< pair<int, int> > qvec[N], svec[N];
int ans[N];

struct ACAM{
    struct node{
        int nx[26];
        int fail;
        void init() {
            memset(nx, -1, sizeof(nx));
            fail = 0;
        }
    }t[N];
    int root, tot, cnt;
    int stt[N], fnt[N];
    vector<int> G[N];
    int newnode() {
        t[++tot].init();
        return tot;
    }
    void init() {
        tot = 0;
        root = newnode();
    }
    int insert(char *s) {
        int len = strlen(s);
        int now = root;
        for (int i = 0; i < len; ++i) {
            if (t[now].nx[s[i] - 'a'] == -1) t[now].nx[s[i] - 'a'] = newnode();
            now = t[now].nx[s[i] - 'a'];
        }
        return now;
    }
    void getFail() {
        for (int i = 0; i < 26; ++i) t[0].nx[i] = 1;
        queue<int> q;
        q.push(1);
        t[1].fail = 0;
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0 ; i < 26; ++i) {
                int v = t[u].nx[i];
                int Fail = t[u].fail;
                if (v == -1) {
                    t[u].nx[i] = t[Fail].nx[i];
                    continue;
                }
                t[v].fail = t[Fail].nx[i];
                q.push(v);
            }
        }
    }
    void getDfn(int u) {
        stt[u] = ++cnt;
        for (auto v : G[u]) {
            getDfn(v);
        }
        fnt[u] = cnt;
    }
    void dfs(int u, int o) {
        b.add(stt[o], 1);
        for (auto [v, id] : qvec[u]) {
            ans[id] = b.query(fnt[v]) - b.query(stt[v] - 1);
        }
        for (auto [ch, v] : svec[u]) {
            int oo = t[o].nx[ch];
            dfs(v, oo);
        }
        b.add(stt[o], -1);
    }
    void solve() {
        getFail();
        cnt = 0;
        for (int i = 1; i <= tot; ++i) {
            G[t[i].fail].push_back(i);
        }
        getDfn(1);
        b.init(tot);
        dfs(0, 1);
    }
}acam;

int n, ord[N];
char s[N];

int main(){
    acam.init();
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        int op = rd();
        if (op == 1) {
            scanf("%s", s);
            svec[0].emplace_back(s[0] - 'a', i);
        } else {
            int id = rd();
            scanf("%s", s);
            svec[id].emplace_back(s[0] - 'a', i);
        }
    }
    int q = rd();
    for (int i = 1; i <= q; ++i) {
        int id = rd();
        scanf("%s", s);
        qvec[id].emplace_back(acam.insert(s), i);
    }
    acam.solve();
    for (int i = 1; i <= q; ++i) {
        printf("%d\n", ans[i]);
    }
    return 0;
}
posted @ 2022-03-15 13:29  stff577  阅读(39)  评论(0编辑  收藏  举报