题目大意
你需要在线维护两种操作:
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
题解
当时学SAM的时候一直不敢做这题,因为我不会LCT。。
听说奥爷爷有splay而非LCT的做法,没去学
这题对于我来说唯一的问题就是怎么知道一个节点子树的总和。。
我们不妨换一个思路,我们一个点维护的不是他Splay的信息,直接就是他原树上的总和
当我们有一个Cut操作时,如果是将x变为一个新的联通块,那就相当于是将root到x的路径全部减去x的值。。
这个只要分离出root和x的路径,然后打个标记就好了
Link的时候也是同样道理
具体看代码
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
const int N=600005*2;
int T;
int len,tot,last;
struct qq
{
int pre,son[26],step;
}s[N];
struct qr
{
int d,fa,rev,son[2],u;
void bt (int x)
{
son[0]=son[1]=fa=rev=0;
d=x;
};
}tr[N];//LCT
bool Is_root(int x)
{
if((tr[tr[x].fa].son[0]!=x)&&(tr[tr[x].fa].son[1]!=x)) return true;
return false;
}
void update (int x)
{
int s1=tr[x].son[0],s2=tr[x].son[1];
if(tr[x].u!=0)
{
int u=tr[x].u;
tr[x].u=0;
tr[s1].d+=u;tr[s2].d+=u;
tr[s1].u+=u;tr[s2].u+=u;
}
if (tr[x].rev)
{
tr[x].rev=false;
tr[s1].rev^=1;tr[s2].rev^=1;
swap(tr[x].son[0],tr[x].son[1]);
}
}
void Rotate(int x)
{
int y=tr[x].fa; int z=tr[y].fa;
int a=tr[y].son[1]==x; int b=tr[z].son[1]==y;
int g=tr[x].son[a^1];
if(!Is_root(y)) tr[z].son[b]=x; tr[x].fa=z;
tr[x].son[a^1]=y; tr[y].fa=x;
tr[y].son[a]=g; if(g) tr[g].fa=y;
update(y);
}
stack<int>S;
void Preserve(int x)
{
while(!Is_root(x)) S.push(x),x=tr[x].fa;
S.push(x);
while(!S.empty()) update(S.top()),S.pop();
}
void Splay(int x)
{
Preserve(x);
while(!Is_root(x))
{
int y=tr[x].fa; int z=tr[y].fa;
int a=tr[y].son[1]==x; int b=tr[z].son[1]==y;
if(Is_root(y)) Rotate(x);
else
{
if(a==b) Rotate(y);
else Rotate(x);
Rotate(x);
}
}update(x);
}
void Access (int x)
{
int last=0;
while (x!=0)
{
Splay(x);
tr[x].son[1]=last;
update(x);
last=x;
x=tr[x].fa;
}
}
void make_root(int x)
{
Access(x);
Splay(x);
tr[x].rev^=1;
}
void Split (int x,int y)
{
make_root(x);
Access(y);
Splay(y);
}
void Link (int x,int y)
{
make_root(y);
tr[y].fa=x;
Split(1,x);
tr[x].u+=tr[x].d;
}
void Cut (int x,int y)//注意,我们是让深度深的连向深度浅的,所以就是说x和这棵树脱离了
{
Split(1,x);
tr[x].u-=tr[x].d;
Split(x,y);
tr[x].fa=tr[y].son[0]=0;
update(y);
}
int find_root(int x)
{
Access(x);
Splay(x);
while (tr[x].son[0]!=0) x=tr[x].son[0];
return x;
}
void ins (int x)
{
//printf("%d\n",x);
int np=++tot,p=last;s[np].step=s[p].step+1;
tr[np].bt(1);
while (p!=0&&s[p].son[x]==0) s[p].son[x]=np,p=s[p].pre;
if (p==0) s[np].pre=1,Link(np,1);
else
{
int q=s[p].son[x];
if (s[q].step==s[p].step+1) s[np].pre=q,Link(np,q);
else
{
int nq=++tot;
tr[nq].bt(0);
s[nq]=s[q];
Link(nq,s[q].pre);/*****/
s[nq].step=s[p].step+1;
Cut(q,s[q].pre);/*****/
s[q].pre=s[np].pre=nq;
Link(q,nq);Link(np,nq);/******/
while (p!=0&&s[p].son[x]==q) s[p].son[x]=nq,p=s[p].pre;
}
}
last=np;
}
char ss[N];
int main()
{
last=tot=1;
scanf("%d",&T);
scanf("%s",ss);len=strlen(ss);
for (int u=0;u<len;u++) ins(ss[u]-'A');
int mask=0;
while (T--)
{
char SS[10];
scanf("%s %s",SS,ss);
len=strlen(ss);
int tmp=mask;
for (int u=0;u<len;u++)
{
tmp=(tmp*131+u)%len;
swap(ss[tmp],ss[u]);
}
if (SS[0]=='A')
for (int u=0;u<len;u++) ins(ss[u]-'A');
else
{
int x=1;
bool tf=false;
for (int u=0;u<len;u++)
{
int c=ss[u]-'A';
if (s[x].son[c]==0) {printf("0\n");tf=true;break;}
x=s[x].son[c];
}
if (!tf)
{
make_root(1);
Access(x);Splay(x);
printf("%d\n",tr[x].d);
mask^=tr[x].d;
}
}
}
return 0;
}