string(AC自动机 在线询问转离线询问)
:链接:https://ac.nowcoder.com/acm/problem/14612?&headNav=acm
来源:牛客网
Bob has a dictionary with N words in it. There are M operators. Each operator is one of two kinds.
1. Add a string to the dictionary. It is guaranteed that the string s was not added before.
2. For the given string s find the number of occurrences of the strings from the dictionary. If some string p from the dictionary has several occurrences in s you should count all of them.
题目大意:首先是T组测试样例,然后先输入n个字符串放在仓库中,然后m次询问,每一次询问有两种类型。类型1是在仓库中新添加一个字符串。类型2是输入一个字符串,然后问当前仓库中有多少字符串是你操作2输入的字符串的子串。
具体思路:一开始是按照在输入新的n个字符串之后建立fail树的,然后每次查询的时候再重新建立一颗fail树(因为考虑到会添加许多新的字符串),然后就T了。既然询问次数达到了1e5.我们就可以考虑在线的强制转换为离线的算法。(多谢旭伟的提醒)
我们先将所有的字符串输入进来,然后再去建fail树。对于每次操作2,我们从输入的顺序倒着来。在初始输入阶段中,当为操作1时,我们保存当前字符串在trie树上的结尾下标。当全部输入完的
时候,倒序查询,每查询完一个,就将这个操作下面添加的字符串操作在trie树上的权值下标取消就好了。
AC代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 # define ll long long
4 # define inf 0x3f3f3f3f
5 const int maxn = 2e5+100;
6 string str;
7 int tot,ch[maxn][30],val[maxn];
8 int fail[maxn],last[maxn];
9 struct node
10 {
11 int type;
12 int end_pos;
13 string str;
14 node() {}
15 node(int xx,int yy)
16 {
17 type=xx,end_pos=yy;
18 }
19 } q[maxn];
20 int sto[maxn];
21 int add()
22 {
23 int p=0;
24 int len=str.size();
25 for(int i=0; i<len; i++)
26 {
27 int u= str[i]-'a';
28 if(!ch[p][u])
29 ch[p][u]=++tot;
30 p=ch[p][u];
31 }
32 val[p]++;
33 return p;
34 }
35 void getfail()
36 {
37 queue<int>q;
38 for(int i=0;i<=tot;i++)fail[i]=-1;
39 q.push(0);
40 while(!q.empty())
41 {
42 int top=q.front();
43 q.pop();
44 for(int i=0; i<26; i++)
45 {
46 int u=ch[top][i];
47 if(u==0)
48 continue;
49 q.push(u);
50 int v=fail[top];
51 while(v!=-1&&!ch[v][i])
52 v=fail[v];
53 fail[u]=(v==-1?0:ch[v][i]);
54 last[u]=val[fail[u]]?fail[u]:last[fail[u]];
55 }
56 }
57 }
58 void init()
59 {
60 for(int i=0; i<=tot; i++)
61 {
62 fail[i]=0,last[i]=0,val[i]=0;
63 for(int j=0; j<30; j++)
64 {
65 ch[i][j]=0;
66 }
67 }
68 tot=0;
69 }
70 int cal(int t)
71 {
72 int ans=0;
73 while(t)
74 {
75 ans+=val[t];
76 t=last[t];
77 }
78 return ans;
79 }
80 int getans(string st)
81 {
82 int ans=0;
83 int len=st.size();
84
85 int p=0;
86 for(int i=0; i<len; i++)
87 {
88 int u=st[i]-'a';
89 while(p&&ch[p][u]==0)
90 p=fail[p];
91 p=ch[p][u];
92 if(val[p])
93 ans+=cal(p);
94 else if(fail[p])
95 {
96 ans+=cal(fail[p]);
97 }
98 }
99 return ans;
100 }
101 int main()
102 {
103 ios::sync_with_stdio(false);
104 int T;
105 cin>>T;
106 //scanf("%d",&T);
107 while(T--)
108 {
109 init();
110 int n,m;
111 cin>>n>>m;
112 //scanf("%d %d",&n,&m);
113 for(int i=1; i<=n; i++)
114 {
115 cin>>str;
116 // scanf("%s",str);
117 add();
118 }
119 getfail();
120 int type;
121 int num=0;
122 while(m--)
123 {
124 cin>>type>>str;
125 //scanf("%d%s",&type,str);
126 if(type==1)
127 {
128 q[++num].type=1;
129 q[num].end_pos=add();
130 }
131 else
132 {
133 q[++num].type=2;
134 q[num].str=str;
135 }
136 }
137 getfail();
138 for(int i=num; i>=1; i--)
139 {
140 if(q[i].type==2)
141 sto[i]=getans(q[i].str);
142 else
143 {
144 val[q[i].end_pos]--;
145 }
146 }
147 for(int i=1; i<=num; i++)
148 {
149 if(q[i].type==2)
150 cout<<sto[i]<<endl;
151 }
152 }
153 return 0;
154 }