Codeforces 163E e-Government

https://codeforces.com/problemset/problem/163/E

题意:给 \(n\) 个串,初始每个串都是有效的,\(m\) 次操作,能让某个串无效,或者某个串重新生效,或者求有效串在新给的 \(s\) 中的总出现次数。

题解:

考虑询问 \(s\) 中出现了多少个模式串,建立ac自动机,对fail树上每个模式串末尾点权值+1,那么 \(s\) 的答案就是在trie上跑,每个点在fail树上到根的链的权值和。

问题变成:给一棵树,单点点权修改,查询点到根的path权值和。

这个的话按dfs序编号,考虑对 \(x\) 单点修改相当于把 \(x\) 所在子树中所有点的答案都增加了 1,用差分树状数组做或者线段树区间加都可。

代码:

/*================================================================
*
*   创 建 者: badcw
*   创建日期: 2020/6/21 5:07
*
================================================================*/
#include <bits/stdc++.h>

#define ll long long
using namespace std;

const int maxn = 1e6+50;
const int mod = 1e9+7;
ll qp(ll a, ll n, ll mod = ::mod) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

int tot;
int pos[maxn], out[maxn];
vector<int> edge[maxn];

void dfs(int u) {
    pos[u] = ++tot;
    for (auto v : edge[u]) dfs(v);
    out[u] = tot;
}

struct AC {
#define M 26
#define fi 'a'
#define tp char
#define lst 0
    int trie[maxn][M], sz, fa[maxn];
    int fail[maxn], deg[maxn];
    int insert(tp *s) {
        int rt = 0;
        for (int i = 0; s[i] != lst; ++i) {
            int nxt = s[i] - fi;
            if (!trie[rt][nxt]) trie[rt][nxt] = ++sz;
            fa[trie[rt][nxt]] = rt;
            rt = trie[rt][nxt];
        }
        return rt;
    }
    void build() {
        queue<int> qu;
        for (int i = 0; i < M; ++i) if (trie[0][i]) {
            fail[trie[0][i]] = 0, qu.push(trie[0][i]);
            edge[0].push_back(trie[0][i]);
        }
        while (!qu.empty()) {
            int k = qu.front();
            qu.pop();
            for (int i = 0; i < M; ++i) {
                if (trie[k][i]) {
                    fail[trie[k][i]] = trie[fail[k]][i];
                    edge[trie[fail[k]][i]].push_back(trie[k][i]);
                    qu.push(trie[k][i]);
                    deg[fail[trie[k][i]]] ++;
                } else trie[k][i] = trie[fail[k]][i];
            }
        }
    }
}ac;

int n, m;
int id[maxn], inv[maxn], vis[maxn];
char s[maxn];

int pre[maxn];
void add(int pos, int k) { while (pos <= tot) pre[pos] += k, pos += pos & -pos; }
int query(int pos) {
    int res = 0;
    while (pos > 0) {
        res += pre[pos];
        pos -= pos & -pos;
    }
    return res;
}

int main(int argc, char* argv[]) {
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%s", s);
        id[i] = ac.insert(s);
        inv[id[i]] = i;
    }
    ac.build();
    dfs(0);
    for (int i = 1; i <= n; ++i) {
//        cerr << pos[id[i]] << " " << out[id[i]] << endl;
        add(pos[id[i]], 1);
        vis[i] = 1;
        add(out[id[i]] + 1, -1);
    }
    while (m--) {
        char t = getchar();
        while (t == ' ' || t == '\n') t = getchar();
        if (t == '+') {
            int x;
            scanf("%d", &x);
            if (vis[x] == 1) continue;
            vis[x] = 1;
            add(pos[id[x]], 1);
            add(out[id[x]] + 1, - 1);
        } else if (t == '-') {
            int x;
            scanf("%d", &x);
            if (vis[x] == 0) continue;
            vis[x] = 0;
            add(out[id[x]] + 1, 1);
            add(pos[id[x]], -1);
        } else {
            scanf("%s", s);
            int rt = 0;
            int res = 0;
            for (int i = 0; s[i]; ++i) {
                int nxt = s[i] - 'a';
                rt = ac.trie[rt][nxt];
//                if (inv[rt]) {
//                    cerr << "add " << pos[rt] << endl;
                    res += query(pos[rt]);
//                }
//                cerr << rt << " " << res << endl;
            }
            printf("%d\n", res);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/badcw/p/13171281.html