Description
给出一个串,然后这个串有28种字符,26个小写英文字母和’B’,’P’两个字母
我们定义一个模式串(一开始这个串是空的)。
假如当前输入的字符是小写英文字母的话,就在模式串的末尾加上这个字母
如果是’B’,就把模式串的末尾给去掉。
如果是’P’,就把当前模式串当作一个新的字符串。
然后给出m个询问,每个询问输入x,y,输出第x个字符串在第y个字符串中出现的次数。
Sample Input
aPaPBbP
3
1 2
1 3
2 3
Sample Output
2
1
0
通过这道题学习了一下fail树,这个结构挺好懂的。
fail树是AC自动机的延伸,你将每个点的fail与这个点连一条边,建出一棵树,那么对于一个节点,它子树里的节点的后缀就都会与这个串相同。
那我们子串其实是一个前缀的后缀,我们采用一个离线的做法,先建好一棵fail树,然后将右端点排一下序,然后每个点的查询就查询这个点的子树的和就好了,当我们建到一个的右端点,就直接树状数组维护一下区间和即可。
#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;
}