AC自动机 建立nlogn个AC自动机
Posted Schenker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AC自动机 建立nlogn个AC自动机相关的知识,希望对你有一定的参考价值。
题意:给你3种操作,1、加入一个串到集合中。 2、删除集合中的某一个串 3、查询集合中的字符串在给定的字符串种出现几次。(同一个串可重复)
解法:建立多个AC自动机,用二进制分组来处理。
加入给你21个串: 分为 16+4+1,再添加一个串的时候,即21+1, 22 = 16+4+1+1 = 16 + 4 + 2。 这样每次加串之后只会有logn个操作,查询也变成logn操作, 对于同一个串建立fair指针的次数就少了。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define max3(a,b,c) max(a,max(b,c)) 12 #define min3(a,b,c) min(a,min(b,c)) 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const LL mod = (int)1e9+7; 16 const int N = 3e5 + 100; 17 struct Node{ 18 static const int m = 26;static const int KN = N; 19 int next[KN][m], fair[KN], tot = 0, mark[KN], mark1[KN], root[20], cnt = 0, si[20]; 20 void Build(int x){ 21 queue<int> q; 22 q.push(x); 23 int pos, p, v; 24 while(!q.empty()){ 25 pos = q.front(), q.pop(); 26 for(int i = 0; i < m; i++){ 27 if(!next[pos][i]) continue; 28 p = fair[pos]; v = next[pos][i]; 29 while(p && !next[p][i]) p = fair[p]; 30 if(p) fair[v] = next[p][i]; 31 else fair[v] = x; 32 q.push(v); 33 mark1[v] = mark1[fair[v]] + mark[v]; 34 } 35 } 36 } 37 void Add(char s[], char ch){ 38 root[++cnt] = ++tot; si[cnt] = 1; 39 int pos = root[cnt]; 40 for(int i = 0; s[i]; i++){ 41 if(!next[pos][s[i]-ch]) next[pos][s[i]-ch] = ++tot; 42 pos = next[pos][s[i]-ch]; 43 } 44 mark[pos]++; 45 while(si[cnt] == si[cnt-1]){ 46 Unit(root[cnt-1], root[cnt]); 47 si[--cnt] *= 2; 48 } 49 Build(root[cnt]); 50 } 51 int Query(char s[], char ch){ 52 int pos, ret = 0; 53 for(int id = 1; id <= cnt; id++){ 54 pos = root[id]; 55 for(int i = 0; s[i]; i++){ 56 while(pos && !next[pos][s[i]-ch]) pos = fair[pos]; 57 if(pos) pos = next[pos][s[i]-ch]; 58 else pos = root[id]; 59 ret += mark1[pos]; 60 } 61 } 62 return ret; 63 } 64 void Unit(int u, int v){ 65 mark[u] += mark[v]; 66 for(int i = 0; i < m; i++){ 67 if(!next[u][i] || !next[v][i]) next[u][i] += next[v][i]; 68 else Unit(next[u][i], next[v][i]); 69 } 70 } 71 }ac[2]; 72 char str[N]; 73 int main(){ 74 int n, k; 75 scanf("%d", &n); 76 while(n--){ 77 scanf("%d%s", &k, str); 78 if(k <= 2) ac[k-1].Add(str, ‘a‘); 79 else { 80 printf("%d\n", ac[0].Query(str, ‘a‘)-ac[1].Query(str, ‘a‘)); 81 fflush(stdout); 82 } 83 } 84 return 0; 85 }
以上是关于AC自动机 建立nlogn个AC自动机的主要内容,如果未能解决你的问题,请参考以下文章
HDU3247 Resource Archiver(AC自动机+BFS+DP)
HDU4057 Rescue the Rabbit(AC自动机+状压DP)