题目大意: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;
}