[NOI2011] 阿狸的打字机
对于一组
考虑 自动机暴力运作的过程
就是在 上沿着 的路径走,每走到一处就暴力跳
碰到一个 就产生 的贡献
即 到根的路径上的点,有多少个能一直跳 碰到
用 建成一棵树
那么碰到 就变成了 的子树中有这个点
这样不难想到离线, 树,把根到当前点的路径在 树上打标记
询问就是问 树中 的子树内有多少个点被打了标记
树状数组即可
(没想到一遍就过了
#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]); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2021-07-13 JZOJ 4496. 【GDSOI 2016】第一题 互补约数