zoukankan      html  css  js  c++  java
  • [NOI 2011] 阿狸的打字机

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=2434

    [算法]

            如果我们预处理出所有的字符串 , 显然是会空间超限的

            但是我们发现 , 该字符串集的字典树的节点树 <= 10 ^ 5

            不妨首先构建AC自动机

            考虑AC自动机的fail树  , 有性质 : 所有包含一个节点所代表字符串的节点一定是它的子树

       那么对于每个询问 , 我们就是要求出在fail树中x的子树中有多少个y

            不妨将询问离线 , DFS这棵字典树 , 用树状数组维护贡献

             时间复杂度 : O(NlogN)

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int N = 2e5 + 10;
    const int ALPHA = 26;
    
    struct edge
    {
            int to , nxt;
    } e[N << 1];
    
    struct query
    {
            int l , r;
            int id;
    } ;
    
    int n , m , timer , tot;
    int ed[N] , l[N] , r[N] , head[N];
    vector< query > q[N];
    int ans[N];
    char s[N];
    
    struct Binary_Indexed_Tree
    {
            int c[N];
            inline int lowbit(int x)
            {
                    return x & (-x);
            }
            inline void modify(int x , int value)
            {
                    for (int i = x; i <= n; i += lowbit(i))
                            c[i] += value;
            }
            inline int query(int now)
            {
                    int ret = 0;
                    if (now < 0) return 0;
                    for (int i = now; i; i -= lowbit(i)) 
                            ret += c[i];
                    return ret; 
            }
            inline int query(int l , int r)
            {
                    return query(r) - query(l - 1);
            }
    } BIT;
    
    struct AC_Automaton
    {
            int sz , rt;
            int fail[N] , child[N][ALPHA] , fa[N];
            inline int new_node()
            {
                    ++sz;
                    fail[sz] = 0;
                    memset(child[sz] , 255 , sizeof(child[sz]));
                    return sz;
            }
            inline void init()
            {
                    sz = 0;
                    rt = new_node();
            }    
            inline void addedge(int u , int v)
            {
                    ++tot;
                    e[tot] = (edge){v , head[u]};
                    head[u] = tot;
            }
            inline void rebuild()
            {
                    queue< int > que;
                    fail[rt] = rt;
                    for (int ch = 0; ch < ALPHA; ch++)
                    {
                            if (child[rt][ch] == -1) 
                                    child[rt][ch] = rt;
                            else
                            {
                                    fail[child[rt][ch]] = rt;
                                    que.push(child[rt][ch]);
                            }
                    }
                    while (!que.empty())
                    {
                            int now = que.front();
                            que.pop();
                            for (int ch = 0; ch < ALPHA; ch++)
                            {
                                    if (child[now][ch] == -1)
                                            child[now][ch] = child[fail[now]][ch];
                                    else
                                    {
                                            fail[child[now][ch]] = child[fail[now]][ch];
                                            que.push(child[now][ch]);
                                    }
                            }
                    }
            }
            inline void dfs(int u , int father)
            {
                    l[u] = ++timer;
                    for (int i = head[u]; i; i = e[i].nxt)
                    {
                            int v = e[i].to;
                            if (v != father && v != u) dfs(v , u);
                    }
                    r[u] = timer;
            }
            inline void getfail()
            {
                    for (int i = 1; i <= sz; i++)    
                            addedge(fail[i] , i); 
                    dfs(rt , 0);
            }
            inline void calc(int u , int father)
            {
                    BIT.modify(l[u] , 1);
                    for (unsigned i = 0; i < q[u].size(); i++)
                            ans[q[u][i].id] = BIT.query(q[u][i].l , q[u][i].r);
                    for (int i = 0; i < ALPHA; i++)
                    {
                            if (fa[child[u][i]] == u)
                                    calc(child[u][i] , u);
                    }
                    BIT.modify(l[u] , -1);
            }
    } ACAM;
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    
    int main()
    {
            
            scanf("%s" , s + 1);
            n = strlen(s + 1);
            ACAM.init();
            int now = ACAM.rt , cnt = 1;
            s[++n] = 'P';
            for (int i = 1; i <= n; i++)
            {
                    if (s[i] == 'B') now = ACAM.fa[now];
                    else if (s[i] == 'P') 
                    {
                            ed[cnt] = now;
                            ++cnt;
                            continue;
                    } else 
                    {
                            if (ACAM.child[now][s[i] - 'a'] != -1) now = ACAM.child[now][s[i] - 'a'];
                            else 
                            {
                                    ACAM.child[now][s[i] - 'a'] = ACAM.new_node();
                                    ACAM.fa[ACAM.sz] = now;
                                    now = ACAM.child[now][s[i] - 'a'];
                            }
                    }
            }
            ACAM.rebuild();
            ACAM.getfail();
            scanf("%d" , &m);
            for (int i = 1; i <= m; i++)
            {
                    int x , y;
                    read(x); read(y);
                    q[ed[y]].push_back((query){l[ed[x]] , r[ed[x]] , i});
            }
            ACAM.calc(1 , 0);
            for (int i = 1; i <= m; i++) printf("%d
    " , ans[i]);
            
            return 0;
        
    }
  • 相关阅读:
    NYOJ 23 取石子(一)
    XYNUOJ 2026 素数环
    XYNUOJ 1756 魔法工会
    XYNUOJ 1784 胜利大逃亡
    NYOJ 18 The Triangle
    NYOJ 737 合并石子
    XYNUOJ 问题 B: 敌兵布阵
    NYOJ 1063 生活的烦恼
    XYNUOJ 1774 最少拦截系统
    XYNUOJ 1248 排队打水问题
  • 原文地址:https://www.cnblogs.com/evenbao/p/10459690.html
Copyright © 2011-2022 走看看