[cf710F]String Set Queries

考虑对于$S$内的每一个串,建立一个ac自动机

类似于线段树的结构去合并,即当有两个ac自动机所含串数量相同,就将这两个ac自动机暴力合并

删除可以再建一组ac自动机,减去即可

由于每一个串至多参与$\log n$次合并,且最终ac自动机个数也为$\log n$,因此总复杂度即为$o(n\log n)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 300005
 4 queue<int>q;
 5 queue<pair<int,int> >qq;
 6 int V,n,p,sz[2][21],r[2][21],nex[N],tot[N],sum[N],ch[N][26];
 7 char s[N];
 8 void build(int r){
 9     nex[r]=r;
10     for(int i=0;i<26;i++)
11         if (ch[r][i]){
12             q.push(ch[r][i]);
13             nex[ch[r][i]]=r;
14         }
15     while (!q.empty()){
16         int k=q.front();
17         q.pop();
18         sum[k]=tot[k]+sum[nex[k]];
19         for(int i=0;i<26;i++)
20             if (ch[k][i]){
21                 int u=nex[k];
22                 while ((u!=r)&&(!ch[u][i]))u=nex[u];
23                 if (ch[u][i])u=ch[u][i];
24                 nex[ch[k][i]]=u;
25                 q.push(ch[k][i]);
26             }
27     }
28 }
29 void add_str(int r){
30     int k=r;
31     for(int i=0;s[i];i++)k=ch[k][s[i]-'a']=++V;
32     tot[k]=1;
33     build(r);
34 }
35 int query_str(int r){
36     int k=r,ans=0;
37     for(int i=0;s[i];i++){
38         while ((k!=r)&&(!ch[k][s[i]-'a']))k=nex[k];
39         if (ch[k][s[i]-'a'])k=ch[k][s[i]-'a'];
40         ans+=sum[k];
41     }
42     return ans;
43 }
44 void merge(int r1,int r2){
45     qq.push(make_pair(r1,r2));
46     while (!qq.empty()){
47         int x=qq.front().first,y=qq.front().second;
48         qq.pop();
49         tot[x]+=tot[y];
50         for(int i=0;i<26;i++)
51             if (ch[y][i]){
52                 if (!ch[x][i])ch[x][i]=ch[y][i];
53                 else qq.push(make_pair(ch[x][i],ch[y][i]));
54             }
55     }
56     build(r1);
57 }
58 void add(int p){
59     int x=sz[p][0];
60     sz[p][++x]=1;
61     add_str(r[p][x]=++V);
62     while ((x>1)&&(sz[p][x]==sz[p][x-1])){
63         sz[p][x-1]+=sz[p][x];
64         merge(r[p][x-1],r[p][x]);
65         x--;
66     }
67     sz[p][0]=x;
68 }
69 int query(int p){
70     int ans=0;
71     for(int i=1;i<=sz[p][0];i++)ans+=query_str(r[p][i]);
72     return ans;
73 }
74 int main(){
75     scanf("%d",&n);
76     for(int i=1;i<=n;i++){
77         scanf("%d%s",&p,s);
78         if (p==1)add(0);
79         if (p==2)add(1);
80         if (p==3){
81             printf("%d\n",query(0)-query(1));
82             fflush(stdout);
83         }
84     }
85 }
View Code

 

posted @ 2020-12-16 10:45  PYWBKTDA  阅读(101)  评论(0编辑  收藏  举报