BZOJ2555:SubString 后缀自动机 LCT
2017-01-04 10:43
363 查看
给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
一个子串出现的次数等于后缀自动机的parent树(也就是反串的后缀树)上这个串对应的节点集合内元素的数量。由parent树的性质可知,这个数量等于子树内反前缀节点的数量。因此对parent树维护LCT,每次新加一个节点后,将这个节点到根的路径size加一,查询时找到需要的节点用LCT查询size值即可。
需要注意的是,nq节点拷贝q节点时要连着size值一起复制。
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
一个子串出现的次数等于后缀自动机的parent树(也就是反串的后缀树)上这个串对应的节点集合内元素的数量。由parent树的性质可知,这个数量等于子树内反前缀节点的数量。因此对parent树维护LCT,每次新加一个节点后,将这个节点到根的路径size加一,查询时找到需要的节点用LCT查询size值即可。
需要注意的是,nq节点拷贝q节点时要连着size值一起复制。
#include<cstdio> #include<cstdlib> #include<cstring> using namespace std; static char pool[158400000]; struct node { //LCT elements node *s[2],*f; int add,v; inline char r(){return this==f->s[0]?0:this==f->s[1]?1:-1;} inline void plus(int x=1){add+=x,v+=x;} inline void down(){if(~r()) f->down();if(add){s[0]->plus(add),s[1]->plus(add),add=0;}} inline void setson(node* p){p->f=p->pa=this;} inline void cutf(); inline int size(); inline void mark(); //SAM elements node *trans[26],*pa; int d; node(int dep=0); inline void* operator new(size_t); inline void copy(node *x) { v=x->v; memcpy(trans,x->trans,sizeof trans); } }*nil=new node; node::node(int dep):f(nil),add(0),v(0),trans(),pa(),d(dep){s[0]=s[1]=nil;} inline void* node::operator new(size_t) { static node* s=(node*)pool; static size_t t=-1; return s+ ++t; } inline void rot(node *x) { static node *o,*y; static char k; k=x->r();if(k==-1) return; k=!k; o=x->f,y=x->s[k]; x->s[k]=o,o->s[!k]=y; if(~(k=o->r())) o->f->s[k]=x; x->f=o->f,o->f=x,y->f=o; } inline void splay(node *x) { x->down(); while(~x->r()) rot(x->r()==x->f->r()?x->f:x),rot(x); } inline void __access(node *x) { static node *y; y=nil; while(x!=nil) { splay(x); x->s[1]=y; y=x; x=x->f; } } inline void access(node *x) { __access(x),splay(x); } inline void chain_add(node *x) { access(x); x->plus(); } inline int getsum(node *x) { splay(x); return x->v; } inline void cut(node *x) { access(x); x->s[0]=x->s[0]->f=nil; } inline void node::mark() { chain_add(this); } inline int node::size() { return getsum(this); } inline void node::cutf() { cut(this); } struct sam { node *rt,*last; sam():rt(new node),last(rt){} inline void push_back(char c) { node *p,*q,*np,*nq; c-='A'; p=last; np=last=new node(p->d+1); while(p&&!p->trans[c]) p->trans[c]=np,p=p->pa; if(!p) {rt->setson(np);goto finish;} q=p->trans[c]; if(p->d+1==q->d) {q->setson(np);goto finish;} nq=new node(p->d+1); q->pa->setson(nq);q->cutf(); nq->copy(q); nq->setson(q);nq->setson(np); while(p&&p->trans[c]==q) p->trans[c]=nq,p=p->pa; finish: np->mark(); } inline size_t count(const char *s) { node *now=rt; while(*s) { now=now->trans[(*s++)-'A']; if(!now) return 0; } return now->size(); } }tr; inline void unzip(char *s,int mask) { int len=strlen(s); for(int i=0;i<len;++i) { mask=(mask*131+i)%len; char t=s[i]; s[i]=s[mask]; s[mask]=t; } } char s[3000001],tp[6]; int q,mask=0; int main() { scanf("%d",&q); scanf("%s",s); for(int i=0;s[i];++i) tr.push_back(s[i]); while(q--) { scanf("%s%s",tp,s); unzip(s,mask); if(*tp=='A') { for(int i=0;s[i];++i) tr.push_back(s[i]); } else { size_t ans=tr.count(s); mask^=ans; printf("%u\n",ans); } } return 0; }
相关文章推荐
- [BZOJ2555]-SubString-后缀自动机+LCT维护parent树
- [BZOJ2555][LCT][后缀自动机]SubString
- bzoj 2555: SubString 后缀自动机+LCT
- 后缀自动机 + LCT 【bzoj2555】SubString
- [BZOJ2555]SubString(后缀自动机+lct)
- bzoj 2555: SubString 后缀自动机+lct
- BZOJ 2555 Substring(后缀自动机+LCT子树维护)
- 【BZOJ2555】SubString 后缀自动机+LCT
- [BZOJ]2555 Substring 后缀自动机&LCT
- BZOJ 2555 SubString LCT 后缀自动机
- [后缀自动机 LCT] BZOJ 2555 SubString
- 【后缀自动机+LCT】BZOJ2555[SubString]题解
- 字符串(LCT,后缀自动机):BZOJ 2555 SubString
- bzoj 2555: SubString 后缀自动机+LCT
- bzoj 2555 SubString 后缀自动机 LCT
- BZOJ 2555: SubString [后缀自动机 LCT]
- BZOJ 2555: SubString 后缀自动机 LCT
- bzoj2555 SubString(后缀自动机+LCT)
- 【bzoj2555】SubString 后缀自动机+LCT
- 【bzoj2555】SubString LCT+后缀自动机