題目大意:m次操作,3種操作,添加一個新串,刪除一個串,給一個串詢問集合裏所有串的出現次數之和。要求強制在線。
維護兩個集合,一個維護增加串,一個用來維護刪除串,結果即爲這兩個集合裏字符串的出現次數之差。由於題目要求強制在線,每次刪減後都要重建AC自動機,但這樣顯然會T掉。所以需要在線的ac自動機。。。
二進制分組。。。。。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<string.h>
using namespace std;
char s[300010];
queue<int>q;
struct Q{
int sum[300010],num[300010],T[300010][30],S[300010][30],fa[300010],A[30],root[30],cnt=0;
void insert(int x,int &f){
if(f==0) f=++cnt;
if(s[x]==0){
sum[f]++;
return;
}
int v=s[x]-'a';
insert(x+1,T[f][v]);
}
void build(int x){
int i,u,v;
fa[x]=x;
for(i=0;i<27;i++){
int v=T[x][i];
if(v){
S[x][i]=v;
fa[v]=x;
q.push(v);
}
else S[x][i]=x;
}
for(;q.size();q.pop()){
u=q.front();
num[u]=num[fa[u]]+sum[u];
for(i=0;i<27;i++){
v=T[u][i];
if(v){
fa[v]=S[fa[u]][i];
S[u][i]=v;
q.push(v);
}
else S[u][i]=S[fa[u]][i];
}
}
}
int merge(int a,int b){
if(a==0||b==0) return a+b;
sum[a]+=sum[b];
int i;
for(i=0;i<27;i++) T[a][i]=merge(T[a][i],T[b][i]);
return a;
}
void add(){
insert(0,root[0]);
int i;
for(i=0;i<=20;i++){
if(A[i]){
root[i+1]=merge(root[i+1],root[i]);
root[i]=A[i]=0;
}
else break;
}
A[i]=1;
build(root[i]);
}
long long qsum(){
int i,p,j;
long long ans=0;
for(i=0;i<=20;i++){
p=root[i];
for(j=0;s[j];j++){
p=S[p][s[j]-'a'];
ans+=num[p];
}
}
return ans;
}
}A,B;
int main(){
int i,n,a;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%s",&a,s);
if(a==1) A.add();
else if(a==2) B.add();
else{
printf("%lld\n",A.qsum()-B.qsum());
fflush(stdout);
}
}
return 0;
}