[阈值 二进制分组 && AC自动机]HDU4787. GRE Words Revenge

来源:互联网 发布:视频云平台 阿里云 编辑:程序博客网 时间:2024/06/07 06:06

如果不强制在线,那么可以分治,所以想到可以二进制分组。
但是询问总长度是 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;}
阅读全文
1 0