牛客练习题 AC自动机 String (强制 离线AC自动机)
嘛,这题TLE了我一下午,最终在晚上终于搞出来了!!!
基本思想是AC自动机,但由于题目是询问中穿插了字符串的添加,所以我们不得不将其离线(因为每次添加都需要更新fail指针,这样时间复杂度太大了),然后倒序处理询问,对之前添加进去的一一删去,得出答案后即可输出。
开始的时候就是普通树状数组的操作,我交的代码TLE是因为我没有做求单词个数过程的优化,我们建立的fail指针并不是每个都指向一个单词的结尾的,所以我们要新建一个last数组对替换fail指针,使得每一个last指针都从一个单词的结尾指向另一个单词的结尾,然后我们计算单词数量的时候时间复杂度就会少很多。于是这样我就过了。。。。嘤嘤嘤
上代码:
#pragma GCC optimize("O2")
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+1;
char str[maxn];
int n,m,tot=0;
int trie[maxn][30],pos[30*maxn],fail[30*maxn],ans[maxn],last[30*maxn];//加了一个last数组终于过了!!!
struct op{
int en_pos,type;
string s;
}pro[maxn];
inline int build(){
int l=strlen(str),root=0;
for(int i=0;i<l;++i){
int id=str[i]-'a';
if(!trie[root][id])
trie[root][id]=++tot;
root=trie[root][id];
}
pos[root]++;
return root;
}
inline void Fail(){
queue<int> Q;
for(int i=0;i<26;++i)
if(trie[0][i])
Q.push(trie[0][i]),fail[trie[0][i]]=0;
while(!Q.empty()){
int x=Q.front();
Q.pop();
for(int i=0;i<26;++i){
int son=trie[x][i];
if(son)
fail[son]=trie[fail[x]][i],Q.push(son);
else
trie[x][i]=trie[fail[x]][i];
last[son]=pos[fail[son]]?fail[son]:last[fail[son]];
}
}
}
inline int cal(int t){
int x=0;
while(t){
x+=pos[t];
t=last[t];
}
return x;
}
inline int getans(int now){
int l=pro[now].s.length(),ans=0,root=0,tt;
for(int i=0;i<l;++i){
int id=pro[now].s[i]-'a';
while(root && !trie[root][id])
root=fail[root];
root=trie[root][id];
if(pos[root])
ans+=cal(root);
else if(fail[root])
ans+=cal(fail[root]);
}
return ans;
}
void init(){
for(int i=0;i<=tot;++i)
fill(trie[i],trie[i]+26,0);
fill(pos,pos+1+tot,0);
fill(last,last+1+tot,0);
tot=0;
}
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;ch=getchar();
}
while(ch>='0'&&ch<='9')
s=s*10+ch-'0',ch=getchar();
return s*w;
}
int main(){
int t;
t=read();
while(t--){
n=read(),m=read();
for(int i=1;i<=n;++i){
scanf("%s",str);
build();
}
for(int i=1;i<=m;++i){
pro[i].type=read();
scanf("%s",str);
if(pro[i].type==1)
pro[i].en_pos=build();
else
pro[i].s=str;
}
Fail();
// debug();
for(int i=m;i>0;--i){
if(pro[i].type==1){
int ppos=pro[i].en_pos;
pos[ppos]--;
}
else
ans[i]=getans(i);
}
for(int i=1;i<=m;++i)
if(pro[i].type==2)
printf("%d\n",ans[i]);
init();
}
return 0 ;
}