Description
懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
Input第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0
读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。HINT:ADD和QUERY操作的字符串都需要解压]
插入字符只需要在SAM上做,询问就是parent树上子树的right集合大小,需要用LCT维护。
但是LCT是不支持对子树的操作的,只需要每次修改一个点的时候,把他到根节点的路径顺便修改。这样就是单链修改,单点查询。注意当且仅当parent树的结构发生改变时需要修改,其他时候只需要下传标记。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[3000010],s1[10];
int fa[3000010],son[3000010][2],trans[3000010][30],val[3000010],
w[3000010],sta[3000010],tag[3000010],
n,q,tot=1,mask,last=1;
int rd(char *s)
{
int l=0;
char c=getchar();
while (c<'A'||c>'Z') c=getchar();
while (c>='A'&&c<='Z')
{
s[++l]=c;
c=getchar();
}
s[l+1]=0;
return l;
}
int rdi()
{
int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
return x;
}
void decode()
{
int x=mask;
for (int i=0;i<n;i++)
{
x=(x*131+i)%n;
swap(s[i+1],s[x+1]);
}
}
int is(int u)
{
return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;
}
void down(int p)
{
if (tag[p])
{
w[p]+=tag[p];
if (son[p][0]) tag[son[p][0]]+=tag[p];
if (son[p][1]) tag[son[p][1]]+=tag[p];
tag[p]=0;
}
}
void rot(int u,int x)
{
int v=son[u][x],p=son[v][x^1],q=fa[u];
if (!is(u)) son[q][son[q][1]==u]=v;
fa[v]=q;
son[v][x^1]=u;
fa[u]=v;
son[u][x]=p;
if (p) fa[p]=u;
}
void splay(int u)
{
int top=0,v,x,y,w;
for (v=u;;v=fa[v])
{
sta[++top]=v;
if (is(v)) break;
}
for (;top;top--) down(sta[top]);
while (!is(u))
{
v=fa[u];
x=son[v][1]==u;
if (is(v)) rot(v,x);
else
{
w=fa[v];
y=son[w][1]==v;
if (x==y)
{
rot(w,y);
rot(v,x);
}
else
{
rot(v,x);
rot(w,y);
}
}
}
}
void access(int u)
{
int t=u,v=0;
while (u)
{
splay(u);
son[u][1]=v;
v=u;
u=fa[u];
}
splay(t);
}
void link(int u,int v)
{
access(v);
fa[u]=v;
down(u);
tag[v]+=w[u];
}
void cut(int u)
{
access(u);
if (son[u][0]) tag[son[u][0]]-=w[u];
son[u][0]=fa[son[u][0]]=0;
}
int findfa(int u)
{
access(u);
int v=son[u][0];
while (son[v][1]) v=son[v][1];
return v;
}
void ins(int c)
{
int p,q,np,nq,tem;
p=last;
val[np=++tot]=val[p]+1;
while (p&&!trans[p][c])
{
trans[p][c]=np;
p=findfa(p);
}
if (!p) link(np,1);
else
{
q=trans[p][c];
if (val[q]==val[p]+1) link(np,q);
else
{
val[nq=++tot]=val[p]+1;
for (int i=1;i<=26;i++) trans[nq][i]=trans[q][i];
tem=findfa(q);
cut(q);
link(nq,tem);
link(q,nq);
link(np,nq);
while (p&&trans[p][c]==q)
{
trans[p][c]=nq;
p=findfa(p);
}
}
}
last=np;
access(np);
tag[np]++;
}
int qry()
{
int p=1;
for (int i=1;i<=n;i++)
if (!trans[p][s[i]-'A'+1]) return 0;
else p=trans[p][s[i]-'A'+1];
access(p);
return w[p];
}
int main()
{
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
int ans;
q=rdi();
n=rd(s);
for (int i=1;i<=n;i++) ins(s[i]-'A'+1);
while (q--)
{
rd(s1);
n=rd(s);
decode();
if (s1[1]=='A')
for (int i=1;i<=n;i++) ins(s[i]-'A'+1);
else
{
printf("%d\n",ans=qry());
mask^=ans;
}
}
}