询问某一个点的出现次数即为求它在
S
A
M
SAM
SAM上对应节点的
e
n
d
p
o
s
endpos
endpos集合大小。于是只需要维护
p
a
r
e
n
t
parent
parent树的
e
n
d
p
o
s
endpos
endpos。
当我们加入一个字符时,可能会涉及到断父亲,连父亲的操作。并且由于新加的这个点有一个新的
e
n
d
p
o
s
endpos
endpos的贡献,需要给它到根节点的路径加
1
1
1。
这恰恰是 L C T LCT LCT可以干的事情:断边,连边,链加。这里的链加恰好是当前点到根节点全部加 1 1 1,于是 a c c e s s access access然后 s p l a y splay splay再打个标记即可。
代码其实就是把 S A M SAM SAM的 b u i l d build build的操作在 L C T LCT LCT上模拟一下。写的时候建议先把 S A M SAM SAM写完,然后照着 b u i l d build build的流程写出在 L C T LCT LCT上的操作,记得 b u i l d build build之后要打标记。
甚至没有 p u s h u p pushup pushup。
#include<bits/stdc++.h>
using namespace std;
const int maxn=6e6+10,ch_set=26;
int Q,mask=0,len,ans;string chars;char s[maxn];
inline void decode(int mask){
scanf("%s",s),chars=s;
for(int j=0;j<chars.length();++j){
mask=(mask*131+j)%chars.length();
swap(chars[j],chars[mask]);
}
}
namespace LCT{
int fa[maxn],son[maxn][2],add[maxn],val[maxn],st[maxn],top;
inline int get(int x){return x==son[fa[x]][1];}
inline void pushdown(int x){
if(add[x]){
if(son[x][0]) add[son[x][0]]+=add[x],val[son[x][0]]+=add[x];
if(son[x][1]) add[son[x][1]]+=add[x],val[son[x][1]]+=add[x];
add[x]=0;
}
}
inline int isroot(int x){return (!fa[x])||(son[fa[x]][0]!=x&&son[fa[x]][1]!=x);}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=get(x),l=son[x][k^1];
if(!isroot(y)) son[z][get(y)]=x;
fa[x]=z,fa[y]=x,son[x][k^1]=y;
fa[l]=y,son[y][k]=l;
}
inline void splay(int x){
st[top=1]=x;
for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
while(top) pushdown(st[top--]);
for(int 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){
for(int y=0;x;y=x,x=fa[x])
splay(x),son[x][1]=y;
}
//将y置做x的父亲。
inline void link(int x,int y){fa[x]=y;}
//江x与x的父亲断开。
inline void cut(int x){
access(x),splay(x);
son[x][0]=fa[son[x][0]]=0;
}
inline void pushnow(int x){
access(x),splay(x);
++val[x],++add[x];
}
inline int query(int x){return access(x),splay(x),val[x];}
}
namespace SAM{
int last,sz;const int root=1;
struct node{int link,nxt[ch_set],len;}st[maxn];
inline void init(){
last=root,sz=root;
st[root].link=0,st[root].len=0;
memset(st[root].nxt,0,sizeof(st[root].nxt));
}
inline void build(int c){
int cur=++sz,p=last;st[cur].len=st[last].len+1;
for(;p&&!st[p].nxt[c];p=st[p].link) st[p].nxt[c]=cur;
if(!p) st[cur].link=root,LCT::link(cur,root);
else{
int q=st[p].nxt[c];
if(st[p].len+1==st[q].len) st[cur].link=q,LCT::link(cur,q);
else{
int clone=++sz;st[clone]=st[q],st[clone].len=st[p].len+1;
LCT::cut(q),LCT::val[clone]=LCT::val[q],LCT::link(clone,st[q].link);
for(;p&&st[p].nxt[c]==q;p=st[p].link)
st[p].nxt[c]=clone;
st[q].link=st[cur].link=clone;
LCT::link(q,clone),LCT::link(cur,clone);
}
}last=cur;
}
inline int query(string t){
int now=root;
for(int i=0;i<t.length();++i){
if(!st[now].nxt[t[i]-'A']) return 0;
now=st[now].nxt[t[i]-'A'];
}return LCT::query(now);
}
}
int main(){
//freopen("bzoj2555.in","r",stdin);
scanf("%d%s",&Q,s),len=strlen(s),SAM::init();
for(int i=0;i<len;++i) SAM::build(s[i]-'A'),LCT::pushnow(SAM::last);
while(Q--){
scanf("%s",s);
if(s[0]=='A'){
decode(mask);
for(int i=0;i<chars.length();++i)
SAM::build(chars[i]-'A'),LCT::pushnow(SAM::last);
}
if(s[0]=='Q'){
decode(mask),ans=SAM::query(chars);
printf("%d\n",ans),mask^=ans;
}
}
}