bzoj2555-SubString
题目
给出一个初始字符串\(s\),支持两种操作:
- 在字符串后面添加一个字符串(\(s+=t\))
- 询问一个字符串在\(s\)中出现了几次
设字符串最终长度为\(n\),询问次数为\(q\),询问字符串总长为\(m\),\(n\le 6\times 10^5, q\le 10^4, m\le 3\times 10^6\)
分析
非常简单的题目。添加字符串用后缀自动机实现,并且用link-cut tree维护后缀树,询问一个字符串出现几次的时候,现在自动机上跑到字符串对应的点\(p\)(如果没有就是无解),再在lct上查询\(p\)的子树中关键点的个数即可。不需要使用TopTree,只需要在每次加点的时候用lct更新链上的点即可。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long giant;
const int maxn=6e5+10;
const int maxl=3e6+10;
const int maxc=26;
char s[maxl];
void decode(char s[],int len,int mask) {
for (int j=0;j<len;++j) {
mask=(int)((giant)mask*131+j)%len;
swap(s[mask],s[j]);
}
}
struct LCT {
struct node {
int ch[2],fa,w,sum,size,tag;
bool rev;
node ():size(1) {}
} t[maxn<<1];
LCT () {t[0].size=0;}
bool isroot(int x) {
return !t[x].fa || t[t[x].fa].ch[rson(x)]!=x;
}
bool rson(int x) {
return t[t[x].fa].ch[1]==x;
}
void update(int x) {
t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
t[x].sum=t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].w;
}
void down(int x) {
if (!isroot(x)) down(t[x].fa);
if (t[x].tag) {
doit(t[x].ch[0],t[x].tag);
doit(t[x].ch[1],t[x].tag);
t[x].tag=0;
}
if (t[x].rev) {
swap(t[x].ch[0],t[x].ch[1]);
if (t[x].ch[0]) t[t[x].ch[0]].rev^=true;
if (t[x].ch[1]) t[t[x].ch[1]].rev^=true;
t[x].rev=false;
}
}
void rotate(int x) {
int f=t[x].fa,d=rson(x),c=t[x].ch[d^1];
if (c) t[c].fa=f;
if (!isroot(f)) t[t[f].fa].ch[rson(f)]=x;
t[x].fa=t[f].fa,t[f].fa=x,t[x].ch[d^1]=f,t[f].ch[d]=c;
update(f);
update(x);
}
void splay(int x) {
down(x);
while (!isroot(x)) if (isroot(t[x].fa)) rotate(x); else {
if (rson(x)==rson(t[x].fa)) rotate(x),rotate(x); else
rotate(t[x].fa),rotate(x);
}
}
void access(int x) {
for (int last=0;x;x=t[last=x].fa) {
splay(x);
t[x].ch[1]=last;
update(x);
}
}
void makeroot(int x) {
access(x);
splay(x);
t[x].rev^=true;
}
void link(int x,int y) {
makeroot(x);
//access(y);
t[x].fa=y;
}
void cut(int x,int y) {
makeroot(x);
access(y);
splay(y);
t[y].ch[0]=t[x].fa=0;
update(y);
update(x);
}
int query(int x,int y) {
makeroot(x);
access(y);
splay(y);
return t[y].sum;
}
void doit(int x,int w) {
t[x].w+=w;
t[x].sum+=t[x].size*w;
t[x].tag+=w;
}
void add(int x,int y,int w) {
makeroot(x);
access(y);
splay(y);
doit(y,w);
}
} lct;
struct SAM {
int t[maxn<<1][maxc],len[maxn<<1],link[maxn<<1],tot,last;
SAM ():tot(1),last(1) {}
void add(int c) {
int nw=++tot,i;
len[nw]=len[last]+1;
for (i=last;i && !t[i][c];i=link[i]) t[i][c]=nw;
if (i) {
int p=t[i][c];
if (len[p]==len[i]+1) link[nw]=p; else {
int q=++tot;
len[q]=len[i]+1;
memcpy(t[q],t[p],sizeof t[p]);
for (int j=i;j && t[j][c]==p;j=link[j]) t[j][c]=q;
int w=lct.query(p,p);
lct.cut(link[p],p);
lct.link(link[p],q);
lct.link(q,p);
lct.add(q,q,w);
link[q]=link[p],link[p]=link[nw]=q;
}
} else link[nw]=1;
lct.link(link[nw],nw);
lct.add(1,nw,1);
last=nw;
}
int run(char s[],int len) {
int now=1;
for (int i=0;i<len;++i) now=t[now][s[i]-'A'];
if (!now) return 0;
int ret=lct.query(now,now);
return ret;
}
} sam;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
int m,mask=0;
scanf("%d",&m);
scanf("%s",s);
int len=strlen(s);
for (int i=0;i<len;++i) sam.add(s[i]-'A');
while (m--) {
static char ord[10];
scanf("%s%s",ord,s);
len=strlen(s);
decode(s,len,mask);
if (ord[0]=='A') for (int i=0;i<len;++i) sam.add(s[i]-'A'); else {
int ans=sam.run(s,len);
mask^=ans;
printf("%d\n",ans);
}
}
return 0;
}