[NOI 2011] 阿狸的打字机
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=2434
[算法]
如果我们预处理出所有的字符串 , 显然是会空间超限的
但是我们发现 , 该字符串集的字典树的节点树 <= 10 ^ 5
不妨首先构建AC自动机
考虑AC自动机的fail树 , 有性质 : 所有包含一个节点所代表字符串的节点一定是它的子树
那么对于每个询问 , 我们就是要求出在fail树中x的子树中有多少个y
不妨将询问离线 , DFS这棵字典树 , 用树状数组维护贡献
时间复杂度 : O(NlogN)
[代码]
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int N = 2e5 + 10; const int ALPHA = 26; struct edge { int to , nxt; } e[N << 1]; struct query { int l , r; int id; } ; int n , m , timer , tot; int ed[N] , l[N] , r[N] , head[N]; vector< query > q[N]; int ans[N]; char s[N]; struct Binary_Indexed_Tree { int c[N]; inline int lowbit(int x) { return x & (-x); } inline void modify(int x , int value) { for (int i = x; i <= n; i += lowbit(i)) c[i] += value; } inline int query(int now) { int ret = 0; if (now < 0) return 0; for (int i = now; i; i -= lowbit(i)) ret += c[i]; return ret; } inline int query(int l , int r) { return query(r) - query(l - 1); } } BIT; struct AC_Automaton { int sz , rt; int fail[N] , child[N][ALPHA] , fa[N]; inline int new_node() { ++sz; fail[sz] = 0; memset(child[sz] , 255 , sizeof(child[sz])); return sz; } inline void init() { sz = 0; rt = new_node(); } inline void addedge(int u , int v) { ++tot; e[tot] = (edge){v , head[u]}; head[u] = tot; } inline void rebuild() { queue< int > que; fail[rt] = rt; for (int ch = 0; ch < ALPHA; ch++) { if (child[rt][ch] == -1) child[rt][ch] = rt; else { fail[child[rt][ch]] = rt; que.push(child[rt][ch]); } } while (!que.empty()) { int now = que.front(); que.pop(); for (int ch = 0; ch < ALPHA; ch++) { if (child[now][ch] == -1) child[now][ch] = child[fail[now]][ch]; else { fail[child[now][ch]] = child[fail[now]][ch]; que.push(child[now][ch]); } } } } inline void dfs(int u , int father) { l[u] = ++timer; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != father && v != u) dfs(v , u); } r[u] = timer; } inline void getfail() { for (int i = 1; i <= sz; i++) addedge(fail[i] , i); dfs(rt , 0); } inline void calc(int u , int father) { BIT.modify(l[u] , 1); for (unsigned i = 0; i < q[u].size(); i++) ans[q[u][i].id] = BIT.query(q[u][i].l , q[u][i].r); for (int i = 0; i < ALPHA; i++) { if (fa[child[u][i]] == u) calc(child[u][i] , u); } BIT.modify(l[u] , -1); } } ACAM; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } int main() { scanf("%s" , s + 1); n = strlen(s + 1); ACAM.init(); int now = ACAM.rt , cnt = 1; s[++n] = 'P'; for (int i = 1; i <= n; i++) { if (s[i] == 'B') now = ACAM.fa[now]; else if (s[i] == 'P') { ed[cnt] = now; ++cnt; continue; } else { if (ACAM.child[now][s[i] - 'a'] != -1) now = ACAM.child[now][s[i] - 'a']; else { ACAM.child[now][s[i] - 'a'] = ACAM.new_node(); ACAM.fa[ACAM.sz] = now; now = ACAM.child[now][s[i] - 'a']; } } } ACAM.rebuild(); ACAM.getfail(); scanf("%d" , &m); for (int i = 1; i <= m; i++) { int x , y; read(x); read(y); q[ed[y]].push_back((query){l[ed[x]] , r[ed[x]] , i}); } ACAM.calc(1 , 0); for (int i = 1; i <= m; i++) printf("%d\n" , ans[i]); return 0; }