[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\n" , ans[i]);
        
        return 0;
    
}

 

posted @ 2019-03-02 08:53  evenbao  阅读(221)  评论(0编辑  收藏  举报