BZOJ2555 SubString【后缀自动机+LCT】

Description

懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。

Input

第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0

读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask=maskxorResult
插入的时候,将TrueStr插到当前字符串后面即可。

HINT:ADD和QUERY操作的字符串都需要解压

长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20

Output

Sample Input

2
A
QUERY B
ADD BBABBBBAAB

Sample Output

0


思路

用LCT来维护prt树的链接关系
直接在extend的时候维护关系就可以了
注意o节点要和先前的节点断开关系
然后顺便维护siz集合的大小就可以了


#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define fu(a,b,c) for(int a=b;a<=c;++a)
#define fd(a,b,c) for(int a=b;a>=c;--a)
#define N 6000010
//Link_Cut_Tree
struct Splay{
  Splay *fa,*ch[2];
  int siz,add;
}_null,*null=&_null;
Splay *newnode(int vl=0){
  Splay *t=new Splay;
  t->siz=vl;
  t->fa=t->ch[1]=t->ch[0]=null;
  return t;
}
bool son(Splay *t){return t->fa->ch[1]==t;}
bool isroot(Splay *t){return t->fa->ch[0]!=t&&t->fa->ch[1]!=t;}
void pushnow(Splay *x,int vl){x->add+=vl;x->siz+=vl;}
void pushdown(Splay *t){
  if(!isroot(t))pushdown(t->fa);
  if(t->add){
    if(t->ch[0]!=null)pushnow(t->ch[0],t->add);
    if(t->ch[1]!=null)pushnow(t->ch[1],t->add);
    t->add=0;
  }
}
void rotate(Splay *t){
  Splay *f=t->fa,*g=f->fa;
  bool a=son(t),b=a^1;
  if(!isroot(f))g->ch[son(f)]=t;
  t->fa=g;
  f->ch[a]=t->ch[b];t->ch[b]->fa=f;
  t->ch[b]=f;f->fa=t;
}
void splay(Splay *t){
  pushdown(t);
  while(!isroot(t)){
    Splay *f=t->fa;
    if(!isroot(f)){
      if(son(t)^son(f))rotate(t);
      else rotate(f);
    }
    rotate(t);
  }
}
void access(Splay *t){
  Splay *tmp=null;
  while(t!=null){
    splay(t);
    t->ch[1]=tmp;
    tmp=t;t=t->fa;
  }
}
void link(Splay *x,Splay *y){
  access(y);
  splay(y);
  x->fa=y;
  pushnow(y,x->siz);
}
void cut(Splay *x){
  access(x);
  splay(x);
  pushnow(x->ch[0],-x->siz);
  x->ch[0]->fa=null;
  x->ch[0]=null;
}
//Suffix_Automaton
const int CHARSET_SIZE=26;
struct Sam{
  Sam *ch[CHARSET_SIZE],*prt;
  Splay *right;
  int maxl;
  Sam(int vl=0,int siz=0){
    prt=NULL;
    memset(ch,0,sizeof(ch));
    maxl=vl;
    right=newnode(siz);
  }
}*root=new Sam,*last=root;
void extend(int c){
  Sam *u=new Sam(last->maxl+1,1),*v=last;
  for(;v&&!v->ch[c];v=v->prt)v->ch[c]=u;
  if(!v){
    u->prt=root;
    link(u->right,root->right);
  }else if(v->maxl+1==v->ch[c]->maxl){
    u->prt=v->ch[c];
    link(u->right,v->ch[c]->right);
  }else{
    Sam *n=new Sam(v->maxl+1,0),*o=v->ch[c];
    copy(o->ch,o->ch+CHARSET_SIZE,n->ch);
    n->prt=o->prt;
    link(n->right,o->prt->right);
    o->prt=u->prt=n;
    cut(o->right);
    link(o->right,n->right);
    link(u->right,n->right);
    for(;v&&v->ch[c]==o;v=v->prt)v->ch[c]=n;
  }
  last=u;
}
//solve and main
char s[N],op[10];
int len,mask=0;
void decode(int m){
  fu(i,0,len-1){
    m=(m*131+i)%len;
    swap(s[i],s[m]);
  }
}
int main(){
  //freopen("input.txt","r",stdin);
  int q;scanf("%d",&q);
  scanf("%s",s);
  len=strlen(s);
  fu(i,0,len-1)extend(s[i]-'A');
  while(q--){
    scanf("%s %s",op,s);
    len=strlen(s);
    decode(mask);
    if(op[0]=='Q'){
      Sam *now=root;
      int can=1;
      fu(i,0,len-1){
        int c=s[i]-'A';
        if(!now->ch[c]){can=0;break;}
        now=now->ch[c];
      }
      if(!can){printf("0\n");continue;}
      splay(now->right);
      mask^=now->right->siz;
      printf("%d\n",now->right->siz);
    }else fu(i,0,len-1)extend(s[i]-'A');
  }
  return 0;
}
posted @ 2018-09-26 19:49  Dream_maker_yk  阅读(250)  评论(1编辑  收藏  举报