[AC自動機 fail樹] [NOI2011]阿狸的打字機
阿新 • • 發佈:2020-07-20
題目
題面
大意就是給定若干字串(輸入方式需要用\(trie\)處理) 然後多組詢問求第\(x\)個列印的串在第\(y\)個列印的串出現幾次。
題解
先建出\(AC\)自動機
考慮第\(x\)個列印的串在第\(y\)個列印的串出現幾次,即等價於有多少屬於\(y\)的字串的\(fail\)指標指向\(x\)的尾結點。
多對一不妨變為一對多的考慮,所以建立\(fail\)樹。
那麼就便成了\(fail\)樹上\(x\)的尾結點指向多少屬於\(y\)的字串。
即\(fail\)樹上\(x\)的子樹中有多少個屬於\(y\)的字串。
那麼現在問題就轉化成了 給定一棵樹,多組詢問,求\(x\)子樹下第\(y\)
所以我們離線處理,在\(trie\)上走,走到\(y\)字串結束時 計算每個\(x\)子樹中的貢獻。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <set> #include <map> #include <queue> using namespace std; template <typename T> void chkmax(T &x, T y) {x = x > y ? x : y;} template <typename T> void chkmin(T &x, T y) {x = x > y ? y : x;} typedef long long ll; const int INF = 2139062143; #define DEBUG(x) std::cerr << #x << " = " << x << std::endl template <typename T> void read (T &x) { x = 0; bool f = 1; char ch; do {ch = getchar(); if (ch == '-') f = 0;} while (ch > '9' || ch < '0'); do {x = x * 10 + ch - '0'; ch = getchar();} while (ch >= '0' && ch <= '9'); x = f ? x : -x; } template <typename T> void write (T x) { if (x < 0) x = ~x + 1, putchar ('-'); if (x > 9) write (x / 10); putchar (x % 10 + '0'); } const int N = 5e5 + 7; int n, cnt, l, num, E, dfs_clock, in[N], fa[N], ans[N], out[N], dfn[N], head[N], fail[N], word[N], cpy[N][26], trie[N][26]; char s[N], p[N]; string ch[N]; vector < int > v[N]; struct EDGE { int to, nxt; } edge[N << 1]; struct Node { int x, y; } a[N]; struct BIT { int sz, c[N]; inline int lowbit(int x) { return x & -x; } inline void add(int i, int x) { for(; i <= sz; i += lowbit(i)) c[i] += x; } inline int sum(int i) { int ret = 0; for(; i; i -= lowbit(i)) ret += c[i]; return ret; } inline int query(int l, int r) { return sum(r) - sum(l - 1); } } bit; inline void addedge(int u, int v) { edge[++E].to = v; edge[E].nxt = head[u]; head[u] = E; } inline void insert(char *s) { int len = strlen(s), now = 0; for(int i = 0; i < len; i++) { if(s[i] == 'B') {now = fa[now]; continue;} if(s[i] == 'P') {word[++num] = now; continue;} int v = s[i] - 'a'; if(!trie[now][v]) trie[now][v] = ++ cnt; fa[trie[now][v]] = now; now = trie[now][v]; } memcpy(cpy, trie, sizeof(trie)); } inline void build() { queue < int > q; for(int i = 0; i < 26; i++) { if(trie[0][i]) { q.push(trie[0][i]); fail[trie[0][i]] = 0; } } while(!q.empty()) { int now = q.front(); q.pop(); for (int i = 0; i < 26; i++) { if(trie[now][i]) { q.push(trie[now][i]); fail[trie[now][i]] = trie[fail[now]][i]; } else { trie[now][i] = trie[fail[now]][i]; } } } for(int i = 1; i <= cnt; i++) addedge(fail[i], i); } inline void dfs(int u) { in[u] = ++ dfs_clock; for(int i = head[u]; i; i = edge[i].nxt) dfs(edge[i].to); out[u] = dfs_clock; } inline void solve(int now) { bit.add(in[now], 1); for(int i = 0; i < v[now].size(); i++) ans[v[now][i]] = bit.query(in[word[a[v[now][i]].x]], out[word[a[v[now][i]].x]]); for(int i = 0; i < 26; i++) if(cpy[now][i]) solve(cpy[now][i]); bit.add(in[now], -1); } int main() { scanf("%s", s); insert(s); build(); dfs(0); read(n); bit.sz = dfs_clock; for(int i = 1; i <= n; i++) { read(a[i].x); read(a[i].y); v[word[a[i].y]].push_back(i); } solve(0); for(int i = 1; i <= n; i++) printf("%d\n", ans[i]); return 0; }