传送门
注意:注释中的那段代码是不能用的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int N=2000010;
struct Edge{int v,nxt;}edge[N];
int head[N],cnt;
int ch[N][26],fail[N],word[N],num;
int st[N],ed[N],tot;
int m,l,len[N],bg[N],que,work[N];
ll c[N],mask,ans,val[N],opt[N];
char s[N],str[N];
void add_edge(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
void insert(char *s,int id){int now=0;for(int i=0;i<len[id];i++){int x=s[i]-'a';if(!ch[now][x]) ch[now][x]=++num;now=ch[now][x];}word[id]=now;
}
void get_fail(){queue<int> q;for(int i=0;i<26;i++){if(ch[0][i]) q.push(ch[0][i]);}while(!q.empty()){int now=q.front();q.pop();for(int i=0;i<26;i++){if(ch[now][i]){fail[ch[now][i]]=ch[fail[now]][i];q.push(ch[now][i]);}else ch[now][i]=ch[fail[now]][i];}}
}
void dfs(int u){st[u]=++tot;for(int i=head[u];i;i=edge[i].nxt) dfs(edge[i].v);ed[u]=tot;
}
void build_fail_tree(){for(int i=1;i<=num;i++)add_edge(fail[i],i);dfs(0);
}
inline int lowbit(int x){return x&(-x);}
void add(int x,int d){for(int i=x;i<=tot;i+=lowbit(i))c[i]+=d;
}
ll getsum(int x){ll sum=0;for(int i=x;i>=1;i-=lowbit(i))sum+=c[i];return sum;
}
void query(int l,int r){que++;int now=0;for(int i=l;i<=r;i++){now=ch[now][s[i]-'a'];if(work[now]==que)//子串在s中已经出现过 ans+=val[now];else{work[now]=que;//val[now]=getsum(ed[now])-getsum(st[now]-1);val[now]=getsum(st[now]);ans+=val[now];}}
}
int main(){scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%lld%s",&opt[i],str);len[i]=strlen(str);bg[i]=l+1;insert(str,i);for(int j=0;j<len[i];j++)s[++l]=str[j];}get_fail();build_fail_tree();for(int i=1;i<=m;i++){opt[i]^=mask;if(opt[i]==1){add(st[word[i]],1);add(ed[word[i]]+1,-1);} //add(st[word[i]],1);else if(opt[i]==2){add(st[word[i]],-1);add(ed[word[i]]+1,1);} //add(st[word[i]],-1);else if(opt[i]==3){ans=0;query(bg[i],bg[i]+len[i]-1);printf("%lld\n",ans);mask^=labs(ans);}}return 0;
}