您的位置:首页 > 其它

BZOJ 2555: SubString 后缀自动机+LCT

2016-12-30 18:33 381 查看
后缀自动机的经典模型,查询一个字符串出现了几次,我们可以联想一下在代码中并未体现的right数组,我们很容易发现,有几个right数组就代表着这个单词出现了几次,那么我们只要设法维护出来就好了,我们可以想到加一个单词在parent树中只对这个单词所在的链有影响,所以我们只要维护一个LCT把parent树维护出来就行了,每次新加节点将parent树对应的链的right+1就行了(据说这题不用LCT更快)

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
struct splay
{
splay *fa,*ls,*rs;
int add_mark,val;
splay(int);
void push_down();
void add(int v);
}*null=new splay(0);
splay :: splay(int _=0)
{
fa=ls=rs=null;
add_mark=0;
val=_;
}
void splay :: add(int v)
{
val+=v;
add_mark+=v;
}
void splay :: push_down()
{
if(add_mark)
{
if(ls!=null) ls->add(add_mark);
if(rs!=null) rs->add(add_mark);
add_mark=0;
}
}
void right(splay *x)
{
splay *y=x->fa;
y->ls=x->rs;
x->rs->fa=y;
x->fa=y->fa;
x->rs=y;
if(y==y->fa->ls) y->fa->ls=x;
else if(y==y->fa->rs) y->fa->rs=x;
y->fa=x;
}
void left(splay *x)
{
splay *y=x->fa;
y->rs=x->ls;
x->ls->fa=y;
x->fa=y->fa;
x->ls=y;
if(y==y->fa->ls) y->fa->ls=x;
else if(y==y->fa->rs) y->fa->rs=x;
y->fa=x;
}
void push_down(splay *x)
{
if(x==x->fa->ls || x==x->fa->rs) push_down(x->fa);
x->push_down();
}
void splaying(splay *x)
{
push_down(x);
while(1)
{
splay *y=x->fa;
splay *z=y->fa;
if(x!=y->ls && x!=y->rs) break;
if(y!=z->ls && y!=z->rs)
{
if(x==y->ls) right(x);
else left(x);
break;
}
if(x==y->ls)
{
if(y==z->ls) right(y);
right(x);
}
else if(x==y->rs)
{
if(y==z->rs) left(y);
left(x);
}
}
}
void access(splay *x)
{
splay *y=null;
while(x!=null)
{
splaying(x);
x->rs=y;
y=x;
x=x->fa;
}
}
void cut(splay *x)
{
access(x);
splaying(x);
x->ls->fa=null;
x->ls=null;
}
void link(splay *x,splay *y)
{
cut(x);
x->fa=y;
}
struct sam
{
sam *parent,*son[26];
int max_len;
splay *tree;
sam(int _=0):parent(0x0),max_len(_)
{
memset(son,0,sizeof(son));
tree=new splay(0);
}
}*root=new sam,*last=root;
void my_insert(int x)
{
sam *p=last;
sam *np=new sam(p->max_len+1);
while(p && !p->son[x])
{
p->son[x]=np;
p=p->parent;
}
if(!p)
{
np->parent=root;
link(np->tree,root->tree);
}
else
{
sam *q=p->son[x];
if(p->max_len==q->max_len-1)
{
np->parent=q;
link(np->tree,q->tree);
}
else
{
sam *nq=new sam(p->max_len+1);
nq->parent=q->parent;
link(nq->tree,q->parent->tree);
memcpy(nq->son,q->son,sizeof(nq->son));
q->parent=nq;np->parent=nq;
link(q->tree,nq->tree);
link(np->tree,nq->tree);
push_down(q->tree);
nq->tree->val=q->tree->val;
while(p && p->son[x]==q)
{
p->son[x]=nq;
p=p->parent;
}
}
}
last=np;
access(np->tree);
splaying(np->tree);
np->tree->add(1);
}
char s[1000000];
int search_ans()
{
sam *o=root;
for(int i=0;s[i];i++)
{
if(!o->son[s[i]-'A']) return 0;
o=o->son[s[i]-'A'];
}
push_down(o->tree);
return o->tree->val;
}
void main_insert()
{
for(int i=0;s[i];i++) my_insert(s[i]-'A');
}
void decode(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 n;
scanf("%d",&n);
scanf("%s",s);
main_insert();
int mask=0;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
if(s[0]=='A')
{
scanf("%s",s);
decode(mask);
main_insert();
}
else if(s[0]=='Q')
{
scanf("%s",s);
decode(mask);
int ans=search_ans();
mask^=ans;
printf("%d\n",ans);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  后缀自动机 BZOJ