[NOI2011] 阿狸的打字机

Solution

对于一组 x,y
考虑 AC 自动机暴力运作的过程
就是在 Trie 上沿着 y 的路径走,每走到一处就暴力跳 fail
碰到一个 x 就产生 1 的贡献
y 到根的路径上的点,有多少个能一直跳 fail 碰到 x
fail 建成一棵树
那么碰到 x 就变成了 x 的子树中有这个点
这样不难想到离线,dfs Trie 树,把根到当前点的路径在 fail 树上打标记
询问就是问 fail 树中 x 的子树内有多少个点被打了标记
树状数组即可
(没想到一遍就过了

Code

#include <cstdio>
#include <cstring>
#define IN inline
using namespace std;
const int N = 1e5 + 5;
int n, ans[N], id[N], cnt, size;
char s[N];
int h[N], tot, hq[N], totq;
struct edge{int to, nxt, id;}e[N], Q[N];
IN void add(int x, int y) {e[++tot] = edge{y, h[x]}, h[x] = tot;}
IN void add(int x, int y, int id) {Q[++totq] = edge{y, hq[x], id}, hq[x] = totq;}
int dfn[N], dfc, siz[N];
void dfs_fail(int x) {
dfn[x] = ++dfc, siz[x] = 1;
for(int i = h[x], v; i; i = e[i].nxt) dfs_fail(v = e[i].to), siz[x] += siz[v];
}
struct BIT {
int c[N];
IN int lowbit(int x) {return x & -x;}
IN void add(int x, int v) {for(; x <= dfc; x += lowbit(x)) c[x] += v;}
IN int query(int x) {int s = 0; for(; x; x -= lowbit(x)) s += c[x]; return s;}
}T;
struct ACAM {
int tr[N][26], fail[N], q[N], fa[N], now, nxt[N][26];
IN ACAM() {now = 0;}
IN void insert(char ch) {
int c = ch - 'a';
if (!tr[now][c]) tr[now][c] = ++size;
fa[tr[now][c]] = now, now = tr[now][c];
}
IN void build() {
for(int i = 0; i <= size; i++)
for(int j = 0; j < 26; j++) nxt[i][j] = tr[i][j];
int h = 0, t = 0, x;
for(int i = 0; i < 26; i++) if (tr[0][i]) q[++t] = tr[0][i];
while (h < t) {
x = q[++h];
for(int i = 0; i < 26; i++)
if (tr[x][i]) fail[tr[x][i]] = tr[fail[x]][i], q[++t] = tr[x][i];
else tr[x][i] = tr[fail[x]][i];
}
for(int i = 1; i <= size; i++) add(fail[i], i);
}
void dfs(int x) {
T.add(dfn[x], 1);
for(int i = hq[x], v; i; i = Q[i].nxt)
ans[Q[i].id] = T.query(dfn[v = Q[i].to] + siz[v] - 1) - T.query(dfn[v] - 1);
for(int i = 0; i < 26; i++)
if (nxt[x][i]) dfs(nxt[x][i]);
T.add(dfn[x], -1);
}
}AC;
int main() {
scanf("%s", s); int len = strlen(s), st = len;
for(int i = 0; i < len; i++)
if (s[i] != 'B' && s[i] != 'P') {st = i; break;}
if (st < len) AC.insert(s[st]);
for(int i = st + 1; i < len; i++)
if (s[i] == 'P') id[++cnt] = AC.now;
else if (s[i] == 'B') AC.now = AC.fa[AC.now];
else AC.insert(s[i]);
AC.build(), scanf("%d", &n);
for(int i = 1, x, y; i <= n; i++) scanf("%d%d", &x, &y), add(id[y], id[x], i);
dfs_fail(0), AC.dfs(0);
for(int i = 1; i <= n; i++) printf("%d\n", ans[i]);
}
posted @   leiyuanze  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-07-13 JZOJ 4496. 【GDSOI 2016】第一题 互补约数
点击右上角即可分享
微信分享提示