(忍不住吐槽一下垃圾CSDN的改版。。一点都不好看还强制改
做了一点fail树相关题 其实好像都没什么好写的。。(阿狸的打字机是众人皆知的了
这道题还是不错的。
我们让S串来构建 AC自动机
建出fail树之后
每加入一个串 就是让走到的所有节点 在fail树上节点到根的距离都+1
但是他是问有多少个串 所以你要让这些树链求并 这样就不会多加了
询问就是问子树和,dfs序+树状数组即可
#include<bits/stdc++.h>
using namespace std;
const int N=2000010,M=100005;
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
return x*f;
}
int f[N][21],t[N][26],tot,n,m,d[N];
int len,fir[N],nex[N],go[N];
void ad(int x,int y){
nex[++len]=fir[x],fir[x]=len,go[len]=y;
}
char c[N];
void ins(int &x){
int len=strlen(c); x=0;
for(int i=0;i<len;++i){
int y=c[i]-'a';
if(!t[x][y])t[x][y]=++tot;
x=t[x][y];
}
}
int q[N],he,ta;
void bulid(){
he=0,ta=0; d[0]=1;
while(he<=ta){
int x=q[he++];
for(int i=0;i<26;++i){
int son=t[x][i],F=f[x][0];
if(son)q[++ta]=son,f[son][0]=x==0?0:t[F][i],d[son]=d[f[son][0]]+1;
else t[x][i]=x==0?0:t[F][i];
}
if(x)ad(f[x][0],x);
}
}
int lca(int x,int y){
if(d[x]<d[y])x^=y^=x^=y; int i;
for(i=20;~i;--i)if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
for(i=20;~i;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
int a[M],in[N],out[N],id,g[N];
void dfs(int x){
in[x]=++id;
for(int i=1;i<21;++i)
if(f[x][i-1])f[x][i]=f[f[x][i-1]][i-1];
else break;
for(int k=fir[x];k;k=nex[k])dfs(go[k]);
out[x]=id;
}
void add(int x,int u){for(;x<=id;x+=x&-x)g[x]+=u;}
int get(int x){int u=0;for(;x;x-=x&-x)u+=g[x];return u;}
int p[N],pl;
int Cmp(int x,int y){return in[x]<in[y];}
void Ins(){
int len=strlen(c),x=0; p[pl=1]=0;
for(int i=0;i<len;++i){
x=t[x][c[i]-'a'];
p[++pl]=x;
}
sort(p+1,p+1+pl,Cmp);
pl=unique(p+1,p+1+pl)-p-1;
add(in[p[1]],1);
for(int i=2;i<=pl;++i){
int l=lca(p[i],p[i-1]);
add(in[p[i]],1);
add(in[l],-1);
}
}
int main(){
int n=read(),i;
for(i=1;i<=n;++i){
scanf("%s",c); ins(a[i]);
}
bulid(); dfs(0);
int q=read();
while(q--){
int u=read();
if(u==1)
scanf("%s",c),Ins();
else
u=read(),printf("%d\n",get(out[a[u]])-get(in[a[u]]-1));
}
return 0;
}