正题

题目链接:https://www.luogu.com.cn/problem/P5212


题目大意

开始一个字符串\(S\),有\(n\)次操作

  1. 在\(S\)末尾加入一个字符串
  2. 询问一个串在\(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;
}

P5212-SubString【LCT,SAM】的更多相关文章

  1. 【BZOJ1036】【LCT版】树的统计Count

    Description 一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. ...

  2. 2594. [WC2006]水管局长数据加强版【LCT+最小生成树】

    Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一 ...

  3. bzoj 4032: [HEOI2015]最短不公共子串【dp+SAM】

    第一.二问: 就是最小的最长公共长度+1,设f[i][j]为a匹配到i,b匹配到j,第一问的转移是f[i][j]=(a[i]==b[j]?f[i-1][j-1]+1:0),第二问的转移是f[i][j] ...

  4. bzoj 2780: [Spoj]8093 Sevenk Love Oimaster【广义SAM】

    AC自动机比较简单,把询问串做成AC自动机然后模板串边跑变更新即可 SAM是把模板串做成广义SAM,然后每个节点存有几个模板串经过,具体方法是每次更新暴力向上跳直到有时间戳我不会证为什么时间复杂度是对 ...

  5. SPOJ-LCS Longest Common Substring 【后缀自动机】

    题目分析: 用没出现过的字符搞拼接.搞出right树,找right集合的最小和最大.如果最小和最大分居两侧可以更新答案. 代码: #include<bits/stdc++.h> using ...

  6. Codeforces 919D Substring 【拓扑排序】+【DP】

    <题目链接> 题目大意:有一个具有n个节点,m条边的有向图,每个点对应一个小写字母,现在给出每个顶点对应的字母以及有向边的连接情况,求经过的某一条路上相同字母出现的最多次数.如果次数无限大 ...

  7. 【算法专题】后缀自动机SAM

    后缀自动机是用于识别子串的自动机. 学习推荐:陈立杰讲稿,本文记录重点部分和感性理解(论文语言比较严格). 刷题推荐:[后缀自动机初探],题目都来自BZOJ. [Right集合] 后缀自动机真正优于后 ...

  8. BZOJ2555 SubString 【后缀自动机 + LCT】

    题目 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 输入 ...

  9. ZJOI2012网络 题解报告【LCT】

    题目描述 有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环,同色的环指相同颜色的边构成的环. 在这 ...

随机推荐

  1. @Profile-根据不同环境注入bean

    介绍 @Profile元注解是在不同的生产环境中,@Bean创建的SpringBean根据spring.profiles.active指定的环境不同创建不同环境的bean对象 一.@Profile元注 ...

  2. ansible 常用模块总结

    记录常用的模块功能,详细使用查看官网. 1. file模块 创建软连接 ansible test -m file -a "src=/tmp/conf.d dest=/tmp/conf.d s ...

  3. Unity遮罩之Mask、RectMask2D与Sprite Mask适用场景分析

    遮罩,顾名思义是一种可以掩盖其它元素的控件.常用于修改其它元素的外观,或限制元素的形状.比如ScrollView或者圆头像效果都有用到遮罩功能.本系列文章希望通过阅读UGUI源码的方式,来探究遮罩的实 ...

  4. css生成彩色阴影

    通常用css生成单色或者同色系的的阴影(box-shadow),其实可以通过巧妙的利用 filter: blur 模糊滤镜,可以生成渐变色或者说是颜色丰富的阴影效果,如图: 原理: 利用伪元素,生成一 ...

  5. ASP.NET Core教程:使用Supervisor做ASP.NET Core应用程序守护进程

    一.前言 在上一篇文章中,我们讲解了如何在Linux服务器上面部署ASP.NET Core应用程序,并且使用Nginx作为反向代理.我们在Linux服务器上面,是通过ASP.NET Core自宿主的方 ...

  6. .NET WebApi 实战第五讲之EntityFramework事务

    在<.NET WebApi 实战第二讲>中我们有提到过事务的概念!任何数据库的读操作可以没有事务,但是写事件必须有事务,如果一个后端工程师在数据库写入时未添加事务,那就不是一个合格的工程师 ...

  7. .net 的析构函数和dispose模式

  8. Javascript - Vue - vuex

    vuex 这是一个与vue配套的公共数据管理工具,可以将一些需要共享的数据保存到vuex中,以此方便项目中的任何组件都可以从vuex中得到共享数据.cnpm i vuex -S 装包 读取数据 //在 ...

  9. opencv入门系列教学(四)处理鼠标事件

    一.鼠标事件的简单演示 opencv中的鼠标事件,值得是任何与鼠标相关的任何事物,例如左键按下,左键按下,左键双击等.我们先来看看鼠标事件有哪些,在python中执行下面代码: import cv2 ...

  10. 配置双jdk

    1 CLASSPATH:.%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar 2 JAVA_HOME:%JAVA_HOME ...