简略题意:中文题目丢链接跑
先考虑建立
ac
自动机,
P
代表当前节点为终止节点,
这样就可以
O(n)
建树。
问第
x
个字符串在
所以我们相当于在fail树上询问,
root
到
y
这条路径上有多少点在
对于一个询问,我们只需要把
root
到
y
这部分点,用
对于多个询问,只需要按
这种题目做着非常爽啊=v=
#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
typedef long long LL;
/*
1. 建立自动机
2. 建立fail树
3. 把所有end节点对应的节点标号记录下来
4. 按y把询问离线(记录id,按id输出答案)
5. 在fail树上获得dfs序
6. 对每个询问,用树状数组处理答案
*/
const int maxn = 500010;
int n;
char buf[maxn];
const int maxs = 26;
struct A {
int x, id;
};
vector<int> G[maxn];
vector<A> ask[maxn];
struct AC {
int next[maxn][maxs], end[maxn], fail[maxn], fa[maxn];
int nxt[maxn][maxs];
int root, L;
int newnode() {
for(int i = 0; i < maxs; i++)
next[L][i] = -1;
fa[L] = 0;
end[L++] = 0;
return L - 1;
}
void init() {
L = 0;
root = newnode();
}
void insert(char buf[]) {
int len = strlen(buf);
int now = root;
int cnt = 0;
for(int i = 0; i < len; i++) {
if(buf[i] == 'P') {
cnt++;
end[cnt] = now;
} else if(buf[i] == 'B'){
now = fa[now];
} else {
int id = buf[i] - 'a';
if(next[now][id] == -1) {
next[now][id] = newnode();
fa[next[now][id]] = now;
}
now = next[now][id];
}
}
}
void build() {
for(int i = 0; i < L; i++)
for(int j = 0; j < maxs; j++)
nxt[i][j] = next[i][j];
queue<int> q;
fail[root] = root;
for(int i = 0; i < maxs; i++) {
if(next[root][i] == -1)
next[root][i] = root;
else {
fail[next[root][i]] = root;
q.push(next[root][i]);
}
}
while(!q.empty()) {
int now = q.front();
q.pop();
for(int i = 0; i < maxs; i++) {
if(next[now][i] == -1)
next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
q.push(next[now][i]);
}
}
}
}
void add(int u, int v) {
G[u].push_back(v);
}
int l[maxn], r[maxn];
int cnt;
int ans[maxn];
void dfs(int u, int fa) {
l[u] = ++cnt;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(v == fa) continue;
dfs(v, u);
}
r[u] = cnt;
}
int C[maxn];
int lowbit(int x) {
return x & -x;
}
void _add(int x, int v) {
for(int i = x; i < maxn; i+=lowbit(i))
C[i]+=v;
}
int _ask(int x) {
int res = 0;
for(int i = x; i; i-=lowbit(i))
res += C[i];
return res;
}
void dfs2(int u) {
if(l[u])
_add(l[u], 1);
for(int i = 0; i < maxs; i++) {
int v = nxt[u][i];
if(v == -1) continue;
dfs2(v);
}
for(int j = 0; j < ask[u].size(); j++) {
int x = ask[u][j].x, id = ask[u][j].id;
int sum = _ask(r[x]) - _ask(l[x]-1);
ans[id] = sum;
}
if(l[u])
_add(l[u], -1);
}
void solve() {
memset(C, 0, sizeof C);
memset(ans, 0, sizeof ans);
cnt = 1;
for(int i = 0; i < L; i++)
if(i != fail[i])
add(fail[i], i);
dfs(root, -1);
int q;
scanf("%d", &q);
int id = 0;
for(int _ = 0; _ < q; _++) {
int u, v;
scanf("%d%d", &u, &v);
ask[end[v]].push_back({end[u], ++id});
}
dfs2(root);
for(int i = 1; i <= q; i++)
printf("%d\n", ans[i]);
}
}solver;
int main() {
while(~scanf("%s", &buf)) {
for(int i = 0; i < maxn; i++)
G[i].clear(), ask[i].clear();
solver.init();
solver.insert(buf);
solver.build();
solver.solve();
}
return 0;
}