bzoj 2434 阿狸的打字机 - Aho-Corasick自动机 - 树状数组
题目传送门
题目大意
阿狸有一个打字机,它有3种键:
- 向缓冲区追加小写字母
- P:打印当前缓冲区(缓冲区不变)
- B:删除缓冲区中最后一个字符
然后多次询问第$x$个被打印出来的串在第$y$个被打印出来的串中出现多少次。
每次查询相当于询问串$x$的结束节点在fail树中的子树包含多少串$y$的点。
又因为这些串的构造比较另类。所以考虑把询问离线,然后用树状数组维护子树中关键点的个数。
Code
1 /** 2 * bzoj 3 * Problem#2434 4 * Accepted 5 * Time: 620ms 6 * Memory: 17792k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <vector> 13 #include <queue> 14 #include <stack> 15 using namespace std; 16 typedef bool boolean; 17 18 const int N = 1e5 + 5; 19 20 typedef class IndexedTree { 21 public: 22 int s; 23 int ar[N]; 24 25 void add(int idx, int val) { 26 for ( ; idx <= s; idx += (idx & (-idx))) 27 ar[idx] += val; 28 } 29 30 int getSum(int idx) { 31 int rt = 0; 32 for ( ; idx; idx -= (idx & (-idx))) 33 rt += ar[idx]; 34 return rt; 35 } 36 }IndexedTree; 37 38 typedef class TrieNode { 39 public: 40 int in, out; 41 TrieNode* ch[26]; 42 TrieNode* fail; 43 }TrieNode; 44 45 TrieNode pool[N]; 46 TrieNode *top = pool; 47 48 TrieNode* newnode() { 49 return ++top; 50 } 51 52 typedef class AhoCorasick { 53 public: 54 TrieNode *rt; 55 56 AhoCorasick():rt(newnode()) { } 57 58 void travel(char* str, TrieNode** ts) { 59 stack<TrieNode*> s; 60 TrieNode* p; 61 s.push(rt); 62 for (int i = 0, c, cp = 0; str[i]; i++) { 63 if (str[i] == 'B') 64 s.pop(); 65 else if (str[i] == 'P') 66 ts[++cp] = s.top(); 67 else { 68 p = s.top(), c = str[i] - 'a'; 69 if (!p->ch[c]) 70 p->ch[c] = newnode(); 71 s.push(p->ch[c]); 72 } 73 } 74 } 75 76 void build(vector<int> *g) { 77 queue<TrieNode*> que; 78 que.push(rt); 79 while (!que.empty()) { 80 TrieNode* p = que.front(); 81 que.pop(); 82 for (int i = 0; i < 26; i++) { 83 TrieNode *np = p->ch[i], *f = p->fail; 84 if (!np) continue; 85 while (f && !f->ch[i]) f = f->fail; 86 if (!f) 87 np->fail = rt; 88 else 89 np->fail = f->ch[i]; 90 que.push(np); 91 } 92 } 93 for (TrieNode* p = top; p != pool + 1; p--) 94 g[p->fail - pool].push_back(p - pool); 95 } 96 }AhoCorasick; 97 98 typedef class Query { 99 public: 100 int x, y, id; 101 102 boolean operator < (Query b) const { 103 return y < b.y; 104 } 105 }Query; 106 107 int m, cnt = 0; 108 char str[N]; 109 int *res; 110 Query *qs; 111 TrieNode** ts; 112 vector<int> g[N]; 113 IndexedTree it; 114 AhoCorasick ac; 115 116 inline void init() { 117 gets(str); 118 scanf("%d", &m); 119 qs = new Query[(m + 1)]; 120 res = new int[(m + 1)]; 121 ts = new TrieNode*[(m + 1)]; 122 for (int i = 1; i <= m; i++) { 123 scanf("%d%d", &qs[i].x, &qs[i].y); 124 qs[i].id = i; 125 } 126 } 127 128 void dfs(int p) { 129 pool[p].in = ++cnt; 130 for (int i = 0; i < (signed) g[p].size(); i++) 131 dfs(g[p][i]); 132 pool[p].out = cnt; 133 } 134 135 inline void solve() { 136 ac.travel(str, ts); 137 ac.build(g); 138 it.s = (top - pool + 1); 139 dfs(1); 140 sort(qs + 1, qs + m + 1); 141 stack<TrieNode*> s; 142 s.push(ac.rt); 143 for (int i = 0, cur = 0, cq = 1; cq <= m && str[i]; i++) { 144 TrieNode *p = s.top(); 145 if (str[i] == 'B') { 146 it.add(p->in, -1); 147 s.pop(); 148 } else if (str[i] == 'P') { 149 cur++; 150 while (cq <= m && qs[cq].y == cur) 151 res[qs[cq].id] = it.getSum(ts[qs[cq].x]->out) - it.getSum(ts[qs[cq].x]->in - 1), cq++; 152 } else { 153 p = p->ch[str[i] - 'a']; 154 it.add(p->in, 1); 155 s.push(p); 156 } 157 } 158 for (int i = 1; i <= m; i++) 159 printf("%d\n", res[i]); 160 } 161 162 int main() { 163 init(); 164 solve(); 165 return 0; 166 }