如果不强制在线,那么可以分治,所以想到可以二进制分组。
但是询问总长度是
5×106
,乘个log看着虚…
可以只建两个AC自动机,当其中一个AC自动机的节点数超过某个值的时候,就把这个自动机与另一个合并,这样询问的总复杂度就是线性的,插入复杂度是 O(nL−−√) 的
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N=500010;
int T,n,cnt,lst,size;
struct NODE{
NODE *c[2],*fail;
int val,w;
NODE(){ val=w=0; c[0]=c[1]=0; }
}a[N],*B,*S;
char s[N*10],t[N*10];
inline void NEW(NODE *&x){
a[cnt].val=a[cnt].w=0; a[cnt].c[0]=a[cnt].c[1]=0;
x=a+cnt; cnt++;
}
inline void Add(NODE *&rt,char *a,int len){
if(!rt) NEW(rt);
NODE *cur=rt;
for(int i=1;i<=len;i++){
if(!cur->c[a[i]-'0']) NEW(cur->c[a[i]-'0']);
cur=cur->c[a[i]-'0'];
}
cur->val=1;
}
NODE *Merge(NODE *&x,NODE *y){
if(!x || !y) return !x?y:x;
x->val|=y->val;
x->c[0]=Merge(x->c[0],y->c[0]);
x->c[1]=Merge(x->c[1],y->c[1]);
return x;
}
NODE *Q[N];
int l,r;
inline void Build(NODE *x){
l=r=1; Q[1]=x;
x->fail=0; x->w=x->val;
while(l<=r){
NODE *u=Q[l++];
for(int i=0;i<2;i++){
NODE *v=u->c[i];
if(!v) continue;
v->w=v->val;
if(u==x) v->fail=0;
else{
NODE *p=u->fail;
while(p && !p->c[i]) p=p->fail;
if(!p) p=x;
v->fail=p->c[i];
if(v->fail) v->w+=v->fail->w;
}
Q[++r]=v;
}
}
}
inline int Query(NODE *rt,char *a,int len){
if(!rt) return 0;
int ret=0; NODE *cur=rt;
for(int i=1;i<=len;i++){
while(cur && !cur->c[a[i]-'0']) cur=cur->fail;
if(!cur) cur=rt;
if(cur->c[a[i]-'0']) cur=cur->c[a[i]-'0'];
ret+=cur->w;
}
return ret;
}
inline bool find(NODE *rt,char *a,int len){
if(!rt) return false;
NODE *cur=rt;
for(int i=1;i<=len;i++){
if(!cur->c[a[i]-'0']) return false;
cur=cur->c[a[i]-'0'];
}
return cur->val;
}
int main(){
scanf("%d",&T); int CASE=0;
while(T--){
printf("Case #%d:\n",++CASE);
scanf("%d",&n);
B=S=0; lst=size=0; int BK=820;
for(int i=1;i<=n;i++){
scanf("%s",s); int len=strlen(s+1);
for(int j=1;j<=len;j++) t[j]=s[(j+lst-1)%len+1];
if(*s=='+'){
if(find(B,t,len)) continue;
Add(S,t,len),size+=len;
if(size>=BK){
B=Merge(B,S); Build(B);
S=0; size=0;
}
else Build(S);
}
else{
printf("%d\n",lst=Query(S,t,len)+Query(B,t,len));
}
}
}
return 0;
}