题目
做法
很好的题目(AC自动机)
支持三种操作:插入,删除,查询
删除很好做,再建个自动机然后差分就行了
题目难点主要是插入,对于每个新来的串都重构,T是肯定的
这题我们用二进制来解决,对于插入和删除建多个自动机,然后查询时累加所属的多个自动机贡献
重点讲下怎么重构吧,反正juruo是第一次了解到,打(*)号的是与平时不同的地方:
inline void F_trie(LL rt){
sum[rt]=0,fail[rt]=rt;
queue<LL>que; que.push(rt);
for(LL i=0;i<26;++i) son[rt][i]=rt;
while(que.size()){
LL u(que.front());que.pop();
sum[u]=sum[fail[u]]+val[u];
for(LL i=0;i<26;++i){
LL v(tmp[u][i]);
if(v){
que.push(v),
fail[v]=son[fail[u]][i],
son[u][i]=v;
}else son[u][i]=son[fail[u]][i];
}
}
}
对于儿子结点,我们开两个数组(tmp暂时储存,son真(*)),这里的结点都不为0(*),每次对于一个自动机添加串,加到(tmp)里
而构造(trie)图时,我们再对(son)进行操作,首先把自动机根结点加入(rt)要遍历的队列,(fail[rt]=rt,son[rt][i]=rt),就如同平时
(0)根节点及空儿子(fail)指向根节点,(fail[v]=son[fail[u]][i], son[u][i]=v;)两句不能颠倒,防止(fail)指正指向自己的情况
My complete code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef int LL;
const LL maxn=300009;
inline LL Read(){
LL x(0),f(1);char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
char s[maxn];
struct ACauto{
LL nod;
LL val[maxn],tmp[maxn][26],son[maxn][26],sum[maxn],fail[maxn],root[25],t[25];
inline void B_trie(LL &rt){
if(!rt) rt=++nod;
LL now=rt;
for(LL i=1,Len=strlen(s+1);i<=Len;++i){
LL c(s[i]-'a');
if(!tmp[now][c]) tmp[now][c]=++nod;
now=tmp[now][c];
}++val[now];
}
inline LL Merge(LL x,LL y){
if(!x||!y) return x+y;
val[x]+=val[y];
for(LL i=0;i<26;++i)
tmp[x][i]=Merge(tmp[x][i],tmp[y][i]);
return x;
}
inline void F_trie(LL rt){
sum[rt]=0,fail[rt]=rt;
queue<LL>que; que.push(rt);
for(LL i=0;i<26;++i) son[rt][i]=rt;
while(que.size()){
LL u(que.front());que.pop();
sum[u]=sum[fail[u]]+val[u];
for(LL i=0;i<26;++i){
LL v(tmp[u][i]);
if(v){
que.push(v),
fail[v]=son[fail[u]][i];
son[u][i]=v;
}else son[u][i]=son[fail[u]][i];
}
}
}
inline void Insert(){
B_trie(root[0]);
LL i(0);
for(;t[i]==1;++i){
root[i+1]=Merge(root[i+1],root[i]);
root[i]=0,
t[i]^=1;
}
t[i]^=1,F_trie(root[i]);
}
inline LL Query(){
LL ret(0),Len=strlen(s+1);
for(LL i=0;i<=21;++i){
if(root[i]==0) continue;
LL now(root[i]);
for(LL j=1;j<=Len;++j){
LL c(s[j]-'a');
now=son[now][c];
ret+=sum[now];
}
}
return ret;
}
}In,Del;
int main(){
LL T=Read();
while(T--){
LL op(Read());
scanf(" %s",s+1);
if(op==1) In.Insert();
else if(op==2) Del.Insert();
else printf("%d
",In.Query()-Del.Query()),fflush(stdout);
}return 0;
}/*
*/