题目链接:https://www.luogu.com.cn/problem/P5212
开始一个字符串S,有n次操作
- 在S末尾加入一个字符串
- 询问一个串在S中出现了多少次
强制在线
强制在线的话,只有SAM能够支持动态插字符了,但是我们平时统计答案的时候要先做一次拓扑排序然后上传信息。
这里要动态维护parents树的话用LCT就好了,就是链修改加单点查询,然后因为根是指定的可以少写很多操作。
时间复杂度O( (n+S)log|S|)
#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)
{fa[x]=y;Access(y);Splay(y);Add(y,w[x]);return;}
void Cut(int 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;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构