AC自动机 建立nlogn个AC自动机

String Set Queries

题意:给你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自动机

 

posted @ 2018-05-20 16:17  Schenker  阅读(220)  评论(0编辑  收藏  举报