首页 > 代码库 > BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree
BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree
题目大意:给定一个初始字符串,提供两种操作:
1.在这个字符串的后面连接一个字符串
2.询问某个字符串在当前串中出现了多少次
SAM大叔的自动机~~
对于每个询问就是在后缀自动机上找到该子串所对应的节点 找不到返回0
然后这个节点的Right集合的大小就是这个子串的出现次数
每次Extend的时候将新建节点沿着parent指针到根的路径上所有点的Right集合大小+1即可
分裂节点的时候要将Right集合一并复制
这方法虽然暴力但是非常有效
由于parent是一棵树,所以可以用LCT来维护这棵树 Extend的时候直接路径修改 O(logn)
结果尼玛反倒变慢了。。。
此外就是解密过程是不改变mask的值的 mask的值只在Query的时候改变 小心被坑
暴力:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int q,mask; char s[3003003]; namespace Suffix_Automaton{ struct SAM{ SAM *son[26],*parent; int dpt,size; SAM(int _=0):parent(0x0),dpt(_),size(0) { memset(son,0,sizeof son); } }*root=new SAM,*last=root; void Extend(int x) { SAM *p=last; SAM *np=new SAM(p->dpt+1); while(p&&!p->son[x]) p->son[x]=np,p=p->parent; if(!p) np->parent=root; else { SAM *q=p->son[x]; if(q->dpt==p->dpt+1) np->parent=q; else { SAM *nq=new SAM(p->dpt+1); memcpy(nq->son,q->son,sizeof nq->son); nq->parent=q->parent; q->parent=nq;np->parent=nq; nq->size=q->size; for(;p&&p->son[x]==q;p=p->parent) p->son[x]=nq; } } last=np; for(;np;np=np->parent) np->size++; } void Insert() { int i; for(i=1;s[i];i++) Extend(s[i]-'A'); } int Query(char *s) { SAM *p; for(p=root;p;p=p->son[(*s++)-'A']) if(!*s) return p->size; return 0; } } void Decode(char s[],int mask) { int i,n=strlen(s); for(i=0;i<n;i++) { mask=(mask*131+i)%n; swap(s[i],s[mask]); } } int main() { int i; char p[100]; cin>>q; scanf("%s",s+1); Suffix_Automaton::Insert(); for(i=1;i<=q;i++) { scanf("%s%s",p,s+1); Decode(s+1,mask); if(p[0]=='Q') { int temp=Suffix_Automaton::Query(s+1); mask^=temp; printf("%d\n",temp); } else Suffix_Automaton::Insert(); } }
LCT:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int q,mask; char s[3003003]; namespace Link_Cut_Tree{ struct abcd{ abcd *fa,*ls,*rs; int val,add_mark; abcd(); void Push_Down(); void Add(int x); }*null=new abcd; abcd :: abcd() { fa=ls=rs=null; val=add_mark=0; } void abcd :: Push_Down() { if(fa->ls==this||fa->rs==this) fa->Push_Down(); if(add_mark) { ls->Add(add_mark); rs->Add(add_mark); add_mark=0; } } void abcd :: Add(int x) { val+=x; add_mark+=x; } void Zig(abcd *x) { abcd *y=x->fa; y->ls=x->rs; x->rs->fa=y; x->rs=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; } void Zag(abcd *x) { abcd *y=x->fa; y->rs=x->ls; x->ls->fa=y; x->ls=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; } void Splay(abcd *x) { x->Push_Down(); while(x->fa->ls==x||x->fa->rs==x) { abcd *y=x->fa,*z=y->fa; if(x==y->ls) { if(y==z->ls) Zig(y); Zig(x); } else { if(y==z->rs) Zag(y); Zag(x); } } } void Access(abcd *x) { abcd *y=null; while(x!=null) { Splay(x); x->rs=y; y=x;x=x->fa; } } void Cut(abcd *x) { Access(x); Splay(x); x->ls->fa=null; x->ls=null; } void Link(abcd *x,abcd *y) { Cut(x); x->fa=y; } } namespace Suffix_Automaton{ struct SAM{ SAM *son[26],*parent; Link_Cut_Tree::abcd *tree; int dpt; SAM(int _=0):parent(0x0),dpt(_) { memset(son,0,sizeof son); tree=new Link_Cut_Tree::abcd; } }*root=new SAM,*last=root; void Extend(int x) { SAM *p=last; SAM *np=new SAM(p->dpt+1); while(p&&!p->son[x]) p->son[x]=np,p=p->parent; if(!p) { np->parent=root; Link_Cut_Tree::Link(np->tree,root->tree); } else { SAM *q=p->son[x]; if(q->dpt==p->dpt+1) { np->parent=q; Link_Cut_Tree::Link(np->tree,q->tree); } else { SAM *nq=new SAM(p->dpt+1); memcpy(nq->son,q->son,sizeof nq->son); nq->parent=q->parent; Link_Cut_Tree::Link(nq->tree,q->parent->tree); q->parent=nq;np->parent=nq; Link_Cut_Tree::Link(q->tree,nq->tree); Link_Cut_Tree::Link(np->tree,nq->tree); //nq->size=q->size; q->tree->Push_Down(); nq->tree->val=q->tree->val; for(;p&&p->son[x]==q;p=p->parent) p->son[x]=nq; } } last=np; //for(;np;np=np->parent) // np->size++; Link_Cut_Tree::Access(np->tree); Link_Cut_Tree::Splay(np->tree); np->tree->Add(1); } void Insert() { int i; for(i=1;s[i];i++) Extend(s[i]-'A'); } int Query(char *s) { SAM *p; for(p=root;p;p=p->son[(*s++)-'A']) if(!*s) return p->tree->Push_Down(),p->tree->val; return 0; } } void Decode(char s[],int mask) { int i,n=strlen(s); for(i=0;i<n;i++) { mask=(mask*131+i)%n; swap(s[i],s[mask]); } } int main() { int i; char p[100]; cin>>q; scanf("%s",s+1); Suffix_Automaton::Insert(); for(i=1;i<=q;i++) { scanf("%s%s",p,s+1); Decode(s+1,mask); if(p[0]=='Q') { int temp=Suffix_Automaton::Query(s+1); mask^=temp; printf("%d\n",temp); } else Suffix_Automaton::Insert(); } }
BZOJ 2555 Substring 后缀自动机+Link-Cut-Tree
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。