题意:
给出一个字符串和m次操作;
每次有两种操作,"ADD"在串后面再加入一个串,"QUERY"查询询问串在整个字符串出现了多少次;
强制在线;
题解:
考虑对原串构建后缀自动机,并利用其为增量法构建的原理维护"ADD"操作;
然后因为这是一个自动机,所以它可以用来识别原串所有的后缀,当识别未完成时,得到的就是一个子串;
那么当延trans指针走了自动机上的某个状态,这个状态的right集合大小就是这个串的出现次数了;
但是right集合不能增量维护,如果直接每次在链上做修改那个复杂度是错的;
所以我们可以用一个数据结构来维护这个修改,那就是LCT了!
虽说如此,LCT不能直接用来维护子树权值的和,但是每次修改造成的影响都是对祖先那一条链上的,这个是可以维护的;
注意在复制结点的时候也要复制right域哦;
时间复杂度O(nlogn);
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 610000
#define M 3100000
#define S 26
using namespace std;
char str[M],op[10];
namespace LCT
{
#define which(x) (ch[fa[x]][1]==x)
int fa[N<<1],ch[N<<1][2],val[N<<1],cov[N<<1];
bool rt[N<<1],rev[N<<1];
void reverse(int x)
{
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void Pushdown(int x)
{
if(rev[x])
{
reverse(ch[x][0]);
reverse(ch[x][1]);
rev[x]=0;
}
if(cov[x])
{
cov[ch[x][0]]+=cov[x];
cov[ch[x][1]]+=cov[x];
val[ch[x][0]]+=cov[x];
val[ch[x][1]]+=cov[x];
cov[x]=0;
}
}
void down(int x)
{
if(!rt[x]) down(fa[x]);
Pushdown(x);
}
void Rotate(int x)
{
int f=fa[x];
bool k=which(x);
ch[f][k]=ch[x][!k];
ch[x][!k]=f;
if(rt[f]) rt[f]^=rt[x]^=1;
else ch[fa[f]][which(f)]=x;
fa[ch[f][k]]=f;
fa[x]=fa[f];
fa[f]=x;
}
void Splay(int x)
{
down(x);
while(!rt[x])
{
int f=fa[x];
if(rt[f])
{
Rotate(x);
break;
}
if(which(x)^which(f))
Rotate(x);
else
Rotate(f);
}
}
void access(int x)
{
int y=0;
while(x)
{
Splay(x);
rt[ch[x][1]]=1;
rt[y]=0;
ch[x][1]=y;
y=x,x=fa[x];
}
}
void Mtr(int x)
{
access(x);
Splay(x);
reverse(x);
}
void update(int x,int v)
{
Mtr(x),access(1),Splay(x);
val[x]+=v;cov[x]+=v;
}
void Link(int x,int y)
{
Mtr(x);
fa[x]=y;
}
void Cut(int x,int y)
{
Mtr(x),access(y),Splay(x);
fa[ch[x][1]]=0;
rt[ch[x][1]]=1;
ch[x][1]=0;
}
int getsum(int x)
{
if(!x) return 0;
Splay(x);
return val[x];
}
#undef which
}
namespace SAM
{
int son[N<<1][S],pre[N<<1],len[N<<1];
bool is[N<<1];
int tot,last;
int newnode(int v)
{
tot++;
is[tot]=v;
LCT::rt[tot]=1;
return tot;
}
void init()
{
tot=0;
last=newnode(0);
}
void replace(int x,int y)
{
if(pre[x])
{
if(is[x])
LCT::update(x,-1);
LCT::Cut(x,pre[x]);
}
LCT::Link(x,y);
if(is[x])
LCT::update(x,1);
pre[x]=y;
}
void Insert(int x)
{
int p,np=newnode(1);
len[np]=len[last]+1;
for(p=last;p&&!son[p][x];p=pre[p])
son[p][x]=np;
if(!p)
replace(np,1);
else
{
int q=son[p][x];
if(len[q]==len[p]+1)
replace(np,q);
else
{
int nq=newnode(0);
len[nq]=len[p]+1;
LCT::Splay(q);
LCT::val[nq]=LCT::val[q]-is[q];
replace(nq,pre[q]);
memcpy(son[nq],son[q],sizeof(int)*S);
replace(np,nq),replace(q,nq);
for(;son[p][x]==q;p=pre[p])
son[p][x]=nq;
}
}
last=np;
}
int query(char *s)
{
int p=1;
while(*s!='\0')
p=son[p][*s-'A'],s++;
return p;
}
}
void decode(char *s,int len,int mask)
{
for(int j=0;j<len;j++)
{
mask=(mask*131+j)%len;
swap(s[j],s[mask]);
}
}
int main()
{
int m,len,i,j,k,mask,ans;
scanf("%d",&m);
scanf("%s",str);
len=strlen(str);
SAM::init();
for(i=0;i<len;i++)
SAM::Insert(str[i]-'A');
for(i=1,mask=0;i<=m;i++)
{
scanf("%s%s",op,str);
len=strlen(str);
decode(str,len,mask);
if(op[0]=='A')
{
for(j=0;j<len;j++)
SAM::Insert(str[j]-'A');
}
else
{
ans=LCT::getsum(SAM::query(str));
printf("%d\n",ans);
mask^=ans;
}
}
return 0;
}