【bzoj2010】SubString【后缀自动机+LCT】
题意:
有2个操作。
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
题解:
建后缀自动机。cnt表示当前状态字符串出现的次数。
每插入一个字符串,就把它插进sam里面,再把往上跳fail走到的节点的cnt值+1。因为当前状态表示的字符串,在fail链上的所有状态肯定也出现了。
每次查询,顺着sam的边走,最后走到的节点的cnt就是答案。
可以想到,把fail链倒过来之后形成的一定是一棵树。所以链上加,直接用link-cut tree维护即可。
注意单点修改后一定要再LCT上splay,access,或者makeroot一下。而且mask穿进解码函数是一个形参!不要直接修改了!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=600005;
int m,l,ans,mask;
char op[10],s[N*5];
void decode(int mm){
for(int i=0;i<l;i++){
mm=(mm*131+i)%l;
swap(s[i],s[mm]);
}
}
struct LCT{
int cnt,ch[N*2][2],fa[N*2],val[N*2],rev[N*2],tag[N*2],stk[N*2];
bool isroot(int u){
return u!=ch[fa[u]][0]&&u!=ch[fa[u]][1];
}
int which(int u){
return u==ch[fa[u]][1];
}
void reverse(int u){
if(!u){
return;
}
rev[u]^=1;
swap(ch[u][0],ch[u][1]);
}
void add(int u,int v){
if(!u){
return;
}
tag[u]+=v;
val[u]+=v;
}
void downtag(int u){
if(rev[u]){
reverse(ch[u][0]);
reverse(ch[u][1]);
rev[u]=0;
}
if(tag[u]){
add(ch[u][0],tag[u]);
add(ch[u][1],tag[u]);
tag[u]=0;
}
}
void pushdown(int u){
stk[stk[0]=1]=u;
for(;!isroot(u);u=fa[u]){
stk[++stk[0]]=fa[u];
}
while(stk[0]){
downtag(stk[stk[0]--]);
}
}
void rotate(int x){
int y=fa[x],md=which(x);
if(!isroot(y)){
ch[fa[y]][which(y)]=x;
}
fa[x]=fa[y];
ch[y][md]=ch[x][!md];
fa[ch[y][md]]=y;
ch[x][!md]=y;
fa[y]=x;
}
void splay(int u){
pushdown(u);
while(!isroot(u)){
if(!isroot(fa[u])){
rotate(which(u)==which(fa[u])?fa[u]:u);
}
rotate(u);
}
}
void access(int u){
for(int v=0;u;v=u,u=fa[u]){
splay(u);
ch[u][1]=v;
}
}
void makeroot(int u){
access(u);
splay(u);
reverse(u);
}
void link(int u,int v){
makeroot(u);
fa[u]=v;
}
void cut(int u,int v){
makeroot(u);
access(v);
splay(v);
fa[u]=ch[v][0]=0;
}
}lct;
struct Sam{
int last,cnt,ch[N*2][26],fa[N*2],len[N*2],siz[N*2];
Sam(){
last=cnt=1;
}
void insert(int x){
int p=last,np=++cnt;
last=np;
len[np]=len[p]+1;
for(;p&&!ch[p][x];p=fa[p]){
ch[p][x]=np;
}
if(!p){
fa[np]=1;
lct.link(np,1);
}else{
int q=ch[p][x];
if(len[q]==len[p]+1){
fa[np]=q;
lct.link(np,q);
}else{
int nq=++cnt;
len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
lct.link(nq,fa[nq]);
lct.cut(q,fa[q]);
fa[q]=fa[np]=nq;
lct.link(q,fa[q]);
lct.link(np,fa[np]);
lct.pushdown(q);
lct.val[nq]=lct.val[q];
lct.access(nq);
for(;ch[p][x]==q;p=fa[p]){
ch[p][x]=nq;
}
}
}
lct.makeroot(1);
lct.access(np);
lct.splay(np);
lct.add(np,1);
}
int query(){
int k=1;
for(int i=0;i<l;i++){
if(!ch[k][s[i]-'A']){
return 0;
}
k=ch[k][s[i]-'A'];
}
lct.access(k);
return lct.val[k];
}
}sam;
int main(){
scanf("%d%s",&m,s);
l=strlen(s);
for(int i=0;i<l;i++){
sam.insert(s[i]-'A');
}
while(m--){
scanf("%s%s",op,s);
l=strlen(s);
decode(mask);
if(op[0]=='A'){
for(int i=0;i<l;i++){
sam.insert(s[i]-'A');
}
}else{
ans=sam.query();
printf("%d\n",ans);
mask^=ans;
}
}
return 0;
}