P5212-SubString【LCT,SAM】
正题
题目链接:https://www.luogu.com.cn/problem/P5212
题目大意
开始一个字符串\(S\),有\(n\)次操作
- 在\(S\)末尾加入一个字符串
- 询问一个串在\(S\)中出现了多少次
强制在线
解题思路
强制在线的话,只有\(\text{SAM}\)能够支持动态插字符了,但是我们平时统计答案的时候要先做一次拓扑排序然后上传信息。
这里要动态维护\(\text{parents}\)树的话用\(\text{LCT}\)就好了,就是链修改加单点查询,然后因为根是指定的可以少写很多操作。
时间复杂度\(O(\ (n+S)\log |S|)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N=6e5*2+10;
int n,cnt,len[N],fa[N],ch[N][26];
char st[N];
struct LCT{
int t[N][2],lazy[N],w[N],fa[N];
stack<int> s;
bool Nroot(int x)
{return fa[x]&&((t[fa[x]][0]==x)||(t[fa[x]][1]==x));}
bool Direct(int x)
{return t[fa[x]][1]==x;}
void Add(int x,int val)
{if(x)w[x]+=val,lazy[x]+=val;return;}
void PushDown(int x){
if(!lazy[x])return;
if(t[x][0])Add(t[x][0],lazy[x]);
if(t[x][1])Add(t[x][1],lazy[x]);
lazy[x]=0;return;
}
void Rotate(int x){
int y=fa[x],z=fa[y];
int xs=Direct(x),ys=Direct(y);
int w=t[x][xs^1];
if(Nroot(y))t[z][ys]=x;
t[y][xs]=w;t[x][xs^1]=y;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
return;
}
void Splay(int x){
int y=x;s.push(x);
while(Nroot(y))y=fa[y],s.push(y);
while(!s.empty())PushDown(s.top()),s.pop();
while(Nroot(x)){
y=fa[x];
if(!Nroot(y))Rotate(x);
else if(Direct(y)==Direct(x))
Rotate(y),Rotate(x);
else Rotate(x),Rotate(x);
}
return;
}
void Access(int x){
for(int y=0;x;y=x,x=fa[x])
Splay(x),t[x][1]=y;
return;
}
void Link(int x,int y)//x为单点,y为树
{fa[x]=y;Access(y);Splay(y);Add(y,w[x]);return;}
void Cut(int x)//将x切断为单点
{Access(x);Splay(x);Add(t[x][0],-w[x]);fa[t[x][0]]=0;t[x][0]=0;return;}
}T;
void decode(char *s,int l,int mask) {
for (int j=0;j<l;j++) {
mask=(mask*131+j)%l;
swap(s[j],s[mask]);
}
return;
}
int insert(int c,int p){
int np=++cnt;len[np]=len[p]+1;T.w[np]++;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1,T.Link(np,1);
else{
int q=ch[p][c];
if(len[p]+1==len[q])fa[np]=q,T.Link(np,q);
else{
int nq=++cnt;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[nq]=fa[q];fa[np]=fa[q]=nq;
T.Cut(q);T.Link(nq,fa[nq]);
T.Link(np,nq);T.Link(q,nq);
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
return np;
}
int main()
{
scanf("%d",&n);
scanf("%s",st);int l=strlen(st);
int p=cnt=1;int mask=0;
for(int i=0;i<l;i++)
p=insert(st[i]-'A',p);
while(n--){
char op[5];
scanf("%s %s",op,st);l=strlen(st);
decode(st,l,mask);
if(op[0]=='Q'){
int x=1;
for(int i=0;i<l;i++)
if(!ch[x][st[i]-'A'])
{x=0;break;}
else x=ch[x][st[i]-'A'];
if(!x)puts("0");
else{
T.Splay(x);
printf("%d\n",T.w[x]);
mask^=T.w[x];
}
}
else{
for(int i=0;i<l;i++)
p=insert(st[i]-'A',p);
}
}
return 0;
}