[Noi2011] Ali's typewriter AC automaton + dfs sequence + tree array

Description
gives a string, then this string has 28 characters, 26 lowercase English letters and two letters 'B', 'P'
We define a pattern string (the string is empty at first).
If the current input character is a lowercase English letter, add this letter to the end of the pattern string.
If it is 'B', remove the end of the pattern string.
If it is 'P', treat the current pattern string as a new string.
Then given m queries, each query input x, y, output the number of times the xth string appears in the yth string.


Sample Input
aPaPBbP
3
1 2
1 3
2 3


Sample Output
2
1
0


I learned about the fail tree through this question, and this structure is very easy to understand.
The fail tree is an extension of the AC automaton. You connect the fail of each point to this point to build a tree, then for a node, the suffixes of the nodes in its subtree will be the same as this string.
Then our substring is actually a suffix of a prefix. We adopt an offline method, first build a fail tree, then sort the right endpoints, and then query each point to query the sum of the subtrees of this point. Well, when we build to the right endpoint of one, we can directly maintain the interval sum in the tree-like array.


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
const int maxn = 210000;

struct edge {
    int x, y, next;
} e[maxn]; int len, last[maxn];
struct trnode {
    int pp, s, f, fail, v[30];
    trnode() {memset(v, -1, sizeof(v));}
} t[maxn]; int cnt, list[maxn];
struct node {
    int x, y, p;
} a[maxn];
int ans[maxn];
int id, s[maxn], cc[maxn], ll[maxn], rr[maxn];
char s1[maxn], ss[maxn];

bool cmp(node a, node b) {return a.y < b.y;}

void ins(int x, int y) {
    e[++len].x = x; e[len].y = y;
    e[len].next = last[x]; last[x] = len;
}

void get_fail() {
    int head = 1, tail = 2;
    list[1] = 0;
    while(head != tail) {
        int x = list[head];
        for(int i = 1; i <= 26; i++) {
            int y = t[x].v[i];
            if(y == -1) continue;
            if(x == 0) t[y].fail = 0;
            else {
                int j = t[x].fail;
                while(j && t[j].v[i] == -1) j = t[j].fail;
                t[y].fail = _max(0, t[j].v[i]);
            }
            list[tail++] = y;
        }
        ins(t[x].fail, x);
        head++;
    }
}

int lowbit(int x) {return x & -x;}
void change(int x, int c) {
    for(int i = x; i <= id; i += lowbit(i)) s[i] += c;
}
int getsum(int x) {
    int sum = 0;
    for(int i = x; i >= 1; i -= lowbit(i)) sum += s[i];
    return sum;
}

void dfs(int x) {
    ll[x] = ++id;
    for(int k = last[x]; k; k = e[k].next) {
        int y = e[k].y;
        if(x != y) dfs(y);
    }
    rr[x] = id;
}

int main() {
    scanf("%s", s1 + 1);
    int n = strlen(s1 + 1);
    int uu = 0, oo = 0, x = 0;
    for(int i = 1; i <= n; i++) {
        if(s1[i] == 'P') {uu++; t[x].s++; cc[uu] = x;}
        else if(s1[i] == 'B') x = t[x].f;
        else {
            int tt = s1[i] - 'a' + 1;
            if(t[x].v[tt] == -1) t[x].v[tt] = ++cnt;
            t[x].s++; t[t[x].v[tt]].f = x; x = t[x].v[tt];
        }
    }
    get_fail();
    dfs(0);
    int now = 0;
    int m; scanf("%d", &m);
    for(int i = 1; i <= m; i++) scanf("%d%d", &a[i].x, &a[i].y), a[i].p = i;
    sort(a + 1, a + m + 1, cmp);
    x = 0; int pp = 1;
    uu = 0, oo = 0;
    for(int i = 1; i <= n; i++) {
        if(s1[i] == 'P') {
            uu++;
            while(a[pp].y == uu) {
                ans[a[pp].p] = getsum(rr[cc[a[pp].x]]) - getsum(ll[cc[a[pp].x]] - 1);
                pp++;
            }
        }
        else if(s1[i] == 'B') {
            change(ll[x], -1);
            x = t[x].f;
        }
        else {
            int tt = s1[i] - 'a' + 1;
            x = t[x].v[tt];
            change(ll[x], 1);
        }
    }
    for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324907937&siteId=291194637