题解:P2414 [NOI2011] 阿狸的打字机
首先最朴素的想法可以分组,每次跑一个 dfs 优化的 ACAM。
换个角度想,我们算得慢的原因是如果不去每次跳 fail 就要跑满一个 \(O(|S|)\) 的 dfs,那如果我能快速的计算我有几个点可以跳 fail 跳到某一个点,那么就可以快速地计算它在我文本串中出现了几次。
我们回想 fail 的结构,他是一个树形的结构,如果我跳 fail 能到一个点,那么意味着我在 fail 树上在他的子树内,这很容易让我们想到 dfn 序维护子树信息。
我们可以对于一个字符串,把他在 trie 树上对应点打标记,树状数组计算子树内标记的个数,当然这样并不能使得分更多。
我们考虑每次打标记,我都要重新跑一遍 trie 树,有很多重复,如果直接在 trie 树上 dfs,到一个点就打上标记,回溯的时候清掉,遇到结束标签再去把他的答案统计掉就可以了。
code:
#include <bits/stdc++.h>
using namespace std;
namespace mlyy {
const int N = 2e5 + 100;
int t[N];
int lowbit(int x) {
return x & (-x);
}
void add(int x, int d) {
for (int i = x;i < N;i += lowbit(i)) t[i] += d;
}
int query(int x) {
int res = 0;
for (int i = x;i;i -= lowbit(i)) {
res += t[i];
}
return res;
}
int idx;
int son[N][26], Son[N][26];
int fa[N];
int fail[N], end[N];
int tag[N];
vector<int> edge[N];
vector<pair<int, int>> q[N];
void get_fail() {
queue<int> q;
for (int i = 0;i < 26;i++) {
if (Son[0][i]) q.push(Son[0][i]);
}
while (q.size()) {
int u = q.front(); q.pop();
for (int i = 0;i < 26;i++) {
int &cur = Son[u][i];
if (cur) {
fail[cur] = Son[fail[u]][i];
q.push(cur);
}
else cur = Son[fail[u]][i];
}
}
for (int i = 1;i <= idx;i++) {
edge[fail[i]].push_back(i);
}
}
int cnt = 0;
int dfn[N], lst[N];
void dfs1(int u) {
dfn[u] = ++cnt;
for (int v : edge[u]) {
dfs1(v);
}
lst[u] = cnt;
}
int ans[N];
void dfs2(int u) {
add(dfn[u], 1);
if (end[u]) {
int y = end[u];
for (auto i : q[y]) {
int x = i.first, id = i.second;
ans[id] = query(lst[tag[x]]) - query(dfn[tag[x]] - 1);
}
}
for (int i = 0;i < 26;i++) {
if (son[u][i]) dfs2(son[u][i]);
}
add(dfn[u], -1);
}
void main() {
string s;
cin >> s;
int n = s.size();
int cnt = 0;
int pos = 0;
for (int i = 0;i < n;i++) {
if ('a' <= s[i] && s[i] <= 'z') {
if (!son[pos][s[i] - 'a']) {
son[pos][s[i] - 'a'] = ++idx;
fa[idx] = pos;
}
pos = son[pos][s[i] - 'a'];
}
if (s[i] == 'B') pos = fa[pos];
if (s[i] == 'P') {
end[pos] = ++cnt;
tag[cnt] = pos;
}
}
for (int i = 0;i <= idx;i++) {
for (int j = 0;j < 26;j++) {
Son[i][j] = son[i][j];
}
}
get_fail();
int m;
cin >> m;
for (int i = 1;i <= m;i++) {
int x, y;
cin >> x >> y;
q[y].push_back({x, i});
}
dfs1(0);
dfs2(0);
for (int i = 1;i <= m;i++) cout << ans[i] << "\n";
}
}
signed main() {
ios :: sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
mlyy::main();
return 0;
}

浙公网安备 33010602011771号