题目大意:
支持两个操作:
1、插入一串字符
2、查询一串字符在串中出现多少次。
强制在线
题目分析:
维护一个动态的字符串,后缀自动机可以做。
要查询一串字符在串中出现的次数,就相当于查询这个串末尾字符代表的状态的right集合的大小,但是我们在维护后缀自动机的时候没办法维护right集合呀!
但是我们可以发现,一个节点的right集合等于在parent树上所有儿子节点的和。
所以只要维护一下所有儿子节点的和就可以了。
因为每次只插入一个点,那就把到根节点路径上的所有节点的right集合都+1。
但是我们要动态的更改和查询这颗树上的点,也就是说这棵树是一颗动态树,那就用LCT来维护一下,在新建节点的时候,和parent树上的父亲Link一下就可以,然后把新建的节点到根的路径整体+1。
(是据说其实暴力更改更快???)
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>
#include <iostream>
using namespace std;
int Q,mask;
char opt[20],s[3000001];
struct splay{
splay *ch[2],*fa;
int sum,mark;
splay();
void add_mark(int mark);
void push_down();
void push_up();
int dir();
}*null=new splay;
splay :: splay()
{
sum=mark=0;
ch[0]=ch[1]=fa=null;
}
void splay :: add_mark(int v)
{
if(this==null) return;
sum+=v;
mark+=v;
return;
}
void splay :: push_down()
{
if(mark)
{
ch[0]->add_mark(mark);
ch[1]->add_mark(mark);
mark=0;
}
return;
}
void splay :: push_up()
{
if(~dir()) fa->push_up();
push_down();
return;
}
int splay :: dir()
{
return fa->ch[0]==this?0:fa->ch[1]==this?1:-1;
}
void turn(splay *c,int d)
{
splay *y=c->ch[d^1];
c->ch[d^1]=y->ch[d];
if(y->ch[d]!=null) y->ch[d]->fa=c;
y->fa=c->fa;
y->ch[d]=c;
int k;
if(~(k=c->dir())) c->fa->ch[k]=y;
c->fa=y;
return;
}
void splaying(splay *c)
{
c->push_up();
int d;
while(~(d=c->dir()))
{
if(d==c->fa->dir()) turn(c->fa->fa,d^1);
turn(c->fa,d^1);
}
return;
}
void Access(splay *c)
{
splay *y=null;
while(c!=null)
{
splaying(c);
c->ch[1]=y;
y=c;
c=c->fa;
}
return;
}
void Cut(splay *x)
{
Access(x),splaying(x);
x->ch[0]->fa=null;
x->ch[0]=null;
return;
}
void Link(splay *x,splay *y)
{
Cut(y);
y->fa=x;
return;
}
struct SAM{
SAM *son[26],*fa;
splay *tree;
int max_len;
SAM(int _);
}*root=new SAM(0),*last=root;
SAM :: SAM(int _):max_len(_)
{
memset(son,0,sizeof(son));
fa=NULL;
tree=new splay;
}
void extend(int x)
{
SAM *p=last;
SAM *np=new SAM(p->max_len+1);
while(p && !p->son[x]) p->son[x]=np,p=p->fa;
if(p==NULL) np->fa=root;
else
{
SAM *q=p->son[x];
if(p->max_len+1==q->max_len) np->fa=q;
else
{
SAM *nq=new SAM(p->max_len+1);
nq->fa=q->fa;
q->tree->push_up();
nq->tree->sum=q->tree->sum;
Link(nq->tree,q->tree);
Link(q->fa->tree,nq->tree);
memcpy(nq->son,q->son,sizeof(nq->son));
q->fa=nq; np->fa=nq;
for(;p&&p->son[x]==q;p=p->fa) p->son[x]=nq;
}
}
last=np;
Link(np->fa->tree,np->tree);
Access(np->tree),splaying(np->tree);
np->tree->add_mark(1);
}
void translate(int mask)
{
static int len;
len=strlen(s);
for(int j=0;j<len;j++)
{
mask=(mask*131+j)%len;
swap(s[j],s[mask]);
}
}
int query()
{
SAM *c=root;
for(int i=0;s[i];i++)
{
if(!c->son[s[i]-'A']) return 0;
c=c->son[s[i]-'A'];
}
c->tree->push_up();
return c->tree->sum;
}
int main()
{
scanf("%d%s",&Q,s);
for(int i=0;s[i];i++) extend(s[i]-'A');
while(Q--)
{
scanf("%s%s",opt,s);
translate(mask);
switch(opt[0])
{
case 'A':
for(int i=0;s[i];i++) extend(s[i]-'A');
break;
case 'Q':
int ans=query();
printf("%d\n",ans);
mask^=ans;
break;
}
}
return 0;
}