【题目描述】
给定一个字符串 A,要求在线支持以下两种操作
opt=A 在字符串A后面添加一个字符串
opt=Q 给定一个字符串 B ,求 B 在 A 中的出现次数。
【思路】
我们可以把B放到A的sam上走,答案即形成的路径的终点的right集合大小。所以问题变成了在线求right集合大小。可考虑新增一个节点,它会对parent-tree一整条链有1的贡献。所以用LCT维护parent-tree,支持链加即可。
代码:
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=2e6+5;
inline int red(){
int data=0;bool w=0;char ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=1,ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return w?-data:data;
}
int n,m,a,b,c,mask=0;
char s[N];
void key(int mask){
scanf("%s",s);int len=strlen(s);
for(int re i=0;i<len;++i)
mask=(mask*131+i)%len,swap(s[i],s[mask]);
}
namespace LCT{
int ch[N][2],fa[N],tag[N],cnt[N],st[N],top=0;
inline bool isroot(int x){return x!=ch[fa[x]][0]&&x!=ch[fa[x]][1];}
inline bool get(int x){return x==ch[fa[x]][1];}
inline void pushnow(int x,int v){if(!x)return;cnt[x]+=v;tag[x]+=v;}
inline void pushdown(int x){
if(!tag[x])return;
pushnow(ch[x][0],tag[x]);
pushnow(ch[x][1],tag[x]);
tag[x]=0;
}
void rotate(int x){
int y=fa[x],z=fa[y],d=get(x);
if(!isroot(y))ch[z][get(y)]=x;
fa[x]=z;fa[y]=x;ch[y][d]=ch[x][d^1];
if(ch[y][d])fa[ch[y][d]]=y;
ch[x][d^1]=y;
}
void splay(int x){
st[top=1]=x;
for(int re i=x;!isroot(i);i=fa[i])st[++top]=fa[i];
while(top)pushdown(st[top--]);
for(int re y=fa[x];!isroot(x);rotate(x),y=fa[x])
if(!isroot(y))rotate(get(x)==get(y)?y:x);
}
inline void access(int x){
int y=0;
for(;x;x=fa[y=x])splay(x),ch[x][1]=y;
pushnow(y,1);
}
inline void link(int x,int y){splay(x);fa[x]=y;}
inline int query(int x){return splay(x),cnt[x];}
}
namespace SAM{
map<char,int>ch[N];
int link[N],len[N],sz=1,last=1;
inline void insert(char c){
int cur=++sz,p=last;
len[cur]=len[p]+1;last=cur;
for(;p&&!ch[p][c];p=link[p])ch[p][c]=cur;
if(!p)return LCT::link(cur,link[cur]=1),LCT::access(cur);
int q=ch[p][c];
if(len[q]==len[p]+1)return LCT::link(cur,link[cur]=q),LCT::access(cur);
else{
int clo=++sz;
len[clo]=len[p]+1;ch[clo]=ch[q];
LCT::cnt[clo]=LCT::query(q);
LCT::link(clo,link[clo]=link[q]);
LCT::link(cur,link[cur]=clo);
LCT::access(cur);
LCT::link(q,link[q]=clo);
for(;p&&ch[p][c]==q;p=link[p])ch[p][c]=clo;
}
}
}
int main(){
m=red();scanf("%s",s);int len=strlen(s);
for(int re i=0;i<len;i++)SAM::insert(s[i]);
while(m--){
scanf("%s",s);
if(s[0]=='A'){
key(mask);int len=strlen(s);
for(int re i=0;i<len;++i)SAM::insert(s[i]);
}else{
key(mask);int len=strlen(s),u=1,ans;
for(int re i=0;i<len;++i)u=SAM::ch[u][s[i]];
if(!u)ans=0;else ans=LCT::query(u);
cout<<ans<<"\n";mask^=ans;
}
}
}