BZOJ2434 [NOI2011]阿狸的打字机

Address


Solution

  • 先把所有输出的字符串建成 T r i e 树,但不用存字符串,因为输入字符的过程就相当于在 T r i e 树上走。
  • 考虑暴力的做法:
    1. 建出 f a i l 指针。
    2. 对于每次查询,沿着第 y 个字符串在 T r i e 树上的节点跳 f a i l ,统计跳到的点是第 x 个字符串结束位置的个数。
    3. 对于相同 y 的询问离线一同处理。
  • 反过来想,对于 T r i e 树上节点 i f a i l [ i ] i 连一条边,建成一棵树,则问题的实质就被转化为求第 x 个字符串结束位置所在的点的子树中有多少个点属于第 y 个字符串。
  • 因此在 T r i e 树上 D F S ,每到一个点打上 + 1 标记,退回上一步时打上 1 标记,则每到达第 y 个字符串的结束位置时,求相关 y 的询问中第 x 个字符串结束位置所在的点的子树和,就是问题的答案了。
  • 直接在树上动态求子树和并不好做(树剖??),所以我们利用 D F S 序,把子树和转化为求序列上的一段区间和,可以用树状数组维护。
  • 时间复杂度 O ( n log n )

Code

#include <cstdio>
#include <iostream>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <algorithm>

using namespace std;

const int N = 1e5 + 5;
int G[N][26], pos[N], idx[N], fa[N], h[N];
int dfn[N], low[N], fail[N], c[N], ans[N]; char s[N];
int n, m, tis, T = 1;

inline int get()
{
    char ch; int res = 0; bool flag = false;
    while (ch = getchar(), !isdigit(ch) && ch != '-');
    (ch == '-' ? flag = true : res = ch ^ 48);
    while (ch = getchar(), isdigit(ch))
        res = res * 10 + ch - 48;
    return flag ? -res : res;
}

struct Question
{
    int x, y, t, s;
    inline bool operator < (const Question &a) const
    {
        return y < a.y;
    }
}q[N], g[N];

struct Edge
{
    int to; Edge *nxt;
}p[N], *lst[N], *P = p;

inline void Link(int x, int y)
{
    (++P)->nxt = lst[x]; lst[x] = P; P->to = y;
}

inline void Bfs()
{
    for (int i = 0; i < 26; ++i) G[0][i] = 1;
    h[1] = 1; int t = 0, w = 1, x, y;
    while (t < w)
    {
        x = h[++t];
        for (int i = 0; i < 26; ++i)
            if (G[x][i])
            {
                h[++w] = G[x][i];
                y = fail[x];
                while (y > 0 && !G[y][i]) y = fail[y];
                fail[G[x][i]] = G[y][i];
            }
    }
}

inline void Dfs1(int x)
{
    dfn[x] = ++tis;
    for (Edge *e = lst[x]; e; e = e->nxt)
        Dfs1(e->to);
    low[x] = tis;
}

inline void Modify(int x, int y)
{
    for (; x <= tis; x += x & -x)
        c[x] += y;
}

inline int Query(int x)
{
    int res = 0;
    for (; x; x -= x & -x)
        res += c[x];
    return res;
}

inline void Dfs2(int x)
{
    Modify(dfn[x], 1);
    if (idx[x])
        for (int i = g[idx[x]].x, im = g[idx[x]].y; i <= im; ++i)
            q[i].s = Query(low[pos[q[i].x]]) - Query(dfn[pos[q[i].x]] - 1);
    for (int i = 0; i < 26; ++i)
        if (G[x][i]) Dfs2(G[x][i]);
    Modify(dfn[x], -1);
}

int main()
{
    scanf("%s", s + 1); int x = 1;
    for (int i = 1, im = strlen(s + 1); i <= im; ++i)
        if (s[i] == 'B')
            x = fa[x];
        else if (s[i] == 'P')
            pos[++n] = x, idx[x] = n;
        else 
        {
            int y = s[i] - 'a';
            if (!G[x][y]) fa[G[x][y] = ++T] = x;
            x = G[x][y];
        }   
    Bfs();
    for (int i = 1; i <= T; ++i) Link(fail[i], i);
    Dfs1(0);
    m = get();
    for (int i = 1; i <= m; ++i)
        q[i].x = get(), q[i].y = get(), q[i].t = i;
    sort(q + 1, q + m + 1);
    int l = 1, r;
    while (l < m)
    {
        r = l;
        while (r < m && q[l].y == q[r + 1].y) ++r;
        g[q[l].y].x = l; g[q[l].y].y = r;
        l = r + 1;
    }
    Dfs2(1);
    for (int i = 1; i <= m; ++i)
        ans[q[i].t] = q[i].s;
    for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/bzjr_log_x/article/details/80813695