题目大意:
给定一个初始字符串
s
s
s,要求支持两种操作:
1.给定一个字符串
t
t
t,字符串
s
s
s后面加一个字符串
t
t
t。
2.给定一个字符串
t
t
t,询问
s
s
s有多少个子串是
t
t
t。
强制在线。
s
s
s最大长长度
≤
6
∗
1
0
5
≤6*10^5
≤6∗105,询问数
≤
1
0
4
≤10^4
≤104,询问串总长
≤
3
∗
1
0
6
≤3*10^6
≤3∗106。
分析:
显然匹配是不合适的,复杂度达到
O
(
∣
s
∣
∗
q
)
O(|s|*q)
O(∣s∣∗q)。
考虑到有字符串总长,可以建出后缀自动机然后在上面跑,
r
i
g
h
t
right
right集大小为解,跳的复杂度与总长有关。
r
i
g
h
t
right
right集相当于每一个前缀节点权值为
1
1
1,其他节点权值为
0
0
0,fail树上该点的子树权值和。
可以使用lct维护fail树。
代码:
/**************************************************************
Problem: 2555
User: ypxrain
Language: C++
Result: Accepted
Time:15476 ms
Memory:180472 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
const int maxn=1200007;
using namespace std;
int n,cnt,now,mask;
char s[maxn],op[20];
struct node{
int l,r,fa,rev;
int sum,data;
}t[maxn];
struct sam{
int fail,len;
int son[26];
}T[maxn];
void updata(int x)
{
int l=t[x].l,r=t[x].r;
t[x].sum=t[l].sum+t[r].sum+t[x].data;
}
bool isroot(int x)
{
return (x!=t[t[x].fa].l) && (x!=t[t[x].fa].r);
}
void rttr(int x)
{
int y=t[x].l;
t[x].l=t[y].r;
if (t[y].r) t[t[y].r].fa=x;
if (x==t[t[x].fa].l) t[t[x].fa].l=y;
else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
t[y].fa=t[x].fa;
t[x].fa=y;
t[y].r=x;
updata(x); updata(y);
}
void rttl(int x)
{
int y=t[x].r;
t[x].r=t[y].l;
if (t[y].l) t[t[y].l].fa=x;
if (x==t[t[x].fa].l) t[t[x].fa].l=y;
else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
t[y].fa=t[x].fa;
t[x].fa=y;
t[y].l=x;
updata(x); updata(y);
}
void remove(int x)
{
if (!isroot(x)) remove(t[x].fa);
if (t[x].rev)
{
t[x].rev^=1;
swap(t[x].l,t[x].r);
if (t[x].l) t[t[x].l].rev^=1;
if (t[x].r) t[t[x].r].rev^=1;
}
}
void splay(int x)
{
remove(x);
while (!isroot(x))
{
int p=t[x].fa,g=t[p].fa;
if (isroot(p))
{
if (x==t[p].l) rttr(p);
else rttl(p);
}
else
{
if (x==t[p].l)
{
if (p==t[g].l) rttr(p),rttr(g);
else rttr(p),rttl(g);
}
else
{
if (p==t[g].l) rttl(p),rttr(g);
else rttl(p),rttl(g);
}
}
}
}
void access(int x)
{
int y=0;
while (x)
{
splay(x);
t[x].data+=t[t[x].r].sum;
t[x].data-=t[y].sum;
t[x].r=y;
updata(x);
y=x,x=t[x].fa;
}
}
void makeroot(int x)
{
access(x);
splay(x);
t[x].rev^=1;
}
void link(int x,int y)
{
makeroot(x);
splay(x);
access(y);
splay(y);
t[y].fa=x;
t[x].data+=t[y].sum;
updata(x);
}
void cut(int x,int y)
{
makeroot(x);
access(y);
splay(y);
t[x].fa=0,t[y].l=0;
updata(y);
}
void build_sam()
{
int p,q,clone;
int L=strlen(s);
for (int i=0;i<L;i++)
{
int c=s[i]-'A';
p=now;
now=++cnt;
T[now].len=T[p].len+1;
t[now].data=t[now].sum=1;
while (p&&(!T[p].son[c])) T[p].son[c]=now,p=T[p].fail;
if (!p) T[now].fail=1,link(1,now);
else
{
q=T[p].son[c];
if (T[p].len+1==T[q].len) T[now].fail=q,link(q,now);
else
{
clone=++cnt;
T[clone]=T[q];
T[clone].len=T[p].len+1;
cut(T[q].fail,q);
link(T[q].fail,clone);
T[now].fail=T[q].fail=clone;
link(clone,q);
link(clone,now);
while (p&&(T[p].son[c]==q)) T[p].son[c]=clone,p=T[p].fail;
}
}
}
}
void getstr(int mask)
{
int L=strlen(s);
for (int j=0;j<L;j++)
{
mask=(mask*131+j)%L;
swap(s[j],s[mask]);
}
}
int getans()
{
int L=strlen(s);
int p=1;
for (int i=0;i<L;i++)
{
int c=s[i]-'A';
if (!T[p].son[c]) return 0;
p=T[p].son[c];
}
makeroot(1);
access(p);
return t[p].data;
}
int main()
{
scanf("%d",&n);
scanf("%s",s);
cnt=now=1;
build_sam();
for (int i=1;i<=n;i++)
{
scanf("%s",op);
scanf("%s",s);
getstr(mask);
if (op[0]=='A') build_sam();
else
{
int d=getans();
mask^=d;
printf("%d\n",d);
}
}
}