• [NOI 2011]阿狸的打字机


    Description

    题库链接

    给你 (n) 个单词, (m) 组询问,每组询问形同 ((x,y)) ,询问 (x) 串在 (y) 串中出现多少次。

    (1leq n,mleq10^5)

    Solution

    比较暴力的做法就是建好 (AC) 自动机后,对于每个 (y) 串暴力跑一遍。看看查询的时候有多少次落在了 (x) 串的末尾。

    我们可以构建 (fail) 树,那么其实题目可以转变为对于 (x) 串末尾节点,其子树中有多少个节点位于 (y) 串上。

    由于题目的特殊性,我们可以离线询问按照 (y) 来排序。并且预处理出 (AC) 自动机的 (dfn)

    我们按照构建 (Trie) 树的操作再按原字符串走一遍。入栈时对应的 (dfn)(+1) ,出时对应的 (dfn)(-1) 。那么走到一个单词节点,所有打上标记的 (dfn) 都是该单词上的。

    注意到一个子树内的 (dfn) 都是连续的,显然就可以回答所有 (y) 等于该单词的询问了。树状数组维护 (dfn) 的标记的前缀和即可。

    Code

    //It is made by Awson on 2018.3.18
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 100000;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    char ch[N+5];
    int n, m, idx, dfn[N+5], size[N+5], ans[N+5], mp[N+5];
    struct tt {int to, next; }edge[(N<<1)+5];
    struct qu {
        int x, y, id;
        bool operator < (const qu &b) const {return y < b.y; }
    }que[N+5];
    int path[N+5], top;
    void add(int u, int v) {edge[++top].to = v, edge[top].next = path[u], path[u] = top; }
    struct bittree {
        int c[N+5];
        void add(int o, int val) {for (; o <= idx; o += lowbit(o)) c[o] += val; }
        int count(int o) {int ans = 0; for (; o; o -= lowbit(o)) ans += c[o]; return ans; }
    }BT;
    struct Trie {
        int ch[N+5][26], pre[N+5], f[N+5], val[N+5], pos;
        void build(char *S) {
        int u = 0;
        for (int i = 0, len = strlen(S); i < len; i++) {
            if (S[i] == 'P') {val[u] = ++n, mp[n] = u; continue; }
            if (S[i] == 'B') {u = pre[u]; continue; }
            if (ch[u][S[i]-'a'] == 0) ++pos, pre[pos] = u, ch[u][S[i]-'a'] = pos;
            u = ch[u][S[i]-'a'];
        }
        }
        void get_fail() {
        queue<int>Q;
        for (int i = 0; i < 26; i++) if (ch[0][i]) f[ch[0][i]] = 0, Q.push(ch[0][i]);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            for (int i = 0; i < 26; i++) {
            if (ch[u][i]) f[ch[u][i]] = ch[f[u]][i], Q.push(ch[u][i]);
            else ch[u][i] = ch[f[u]][i];
            }
        }
        for (int i = 1; i <= pos; i++) add(f[i], i);
        }
        void query(char *S) {
        int loc = 1, u = 0;
        for (int i = 0, len = strlen(S); i < len; i++) {
            if (S[i] == 'P') {
            while (loc <= m && que[loc].y == val[u])
                ans[que[loc].id] = BT.count(dfn[mp[que[loc].x]]+size[mp[que[loc].x]]-1)-BT.count(dfn[mp[que[loc].x]]-1), ++loc;
            }else if (S[i] == 'B') BT.add(dfn[u], -1), u = pre[u];
            else u = ch[u][S[i]-'a'], BT.add(dfn[u], 1);
        }
        }
    }T;
    void dfs(int o) {
        size[o] = 1, dfn[o] = ++idx;
        for (int i = path[o]; i; i = edge[i].next) {
        dfs(edge[i].to); size[o] += size[edge[i].to];
        }
    }
    
    void work() {
        scanf("%s", ch); T.build(ch); T.get_fail();
        dfs(0); read(m);
        for (int i = 1; i <= m; i++) read(que[i].x), read(que[i].y), que[i].id = i;
        sort(que+1, que+1+m); T.query(ch);
        for (int i = 1; i <= m; i++) writeln(ans[i]);
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    URL Rewrite
    Visual Studio调试Asp程序
    IE6下雪碧图多次请求fix方法
    使用antixss防御xss
    字典及其增删改查,解构用法
    逻辑运算,编码问题
    字符串数据类型及其用法
    数据类型,if 语句,while语句
    列表和字典循环遍历时的删除问题,集合
    列表,及其增删改查,元组
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8597314.html
Copyright © 2020-2023  润新知