题目大意:给定一个初始字符串,提供两种操作:
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();
}
}