【BZOJ2555】SubString

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操作的字符串都需要解压

Output

Sample Input

2
A
QUERY B
ADD BBABBBBAAB

Sample Output

0

HINT

40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000

题解:将串扔到SAM里,答案就是S的子树中结束节点的个数,由于强制在线只能用LCT维护,加入一个结束节点就将它到根的路径上的所有点权都+1。

discuss说不能用递归来下传标记?不明觉厉,写的非递归。

一开始写的太丑了,然后开始%黄学长的代码,%了一天一夜才搞出来QAQ

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=1200010;
int msk,n,m,ans,len;
struct LCT
{
int ch[maxn][2],s[maxn],tag[maxn],fa[maxn],q[maxn];
int isr(int x) {return (ch[fa[x]][0]!=x)&&(ch[fa[x]][1]!=x);}
void pushdown(int x)
{
if(ch[x][0]) s[ch[x][0]]+=tag[x],tag[ch[x][0]]+=tag[x];
if(ch[x][1]) s[ch[x][1]]+=tag[x],tag[ch[x][1]]+=tag[x];
tag[x]=0;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],d=(x==ch[y][1]);
if(!isr(y)) ch[z][y==ch[z][1]]=x;
fa[x]=z,fa[y]=x,ch[y][d]=ch[x][d^1];
if(ch[x][d^1]) fa[ch[x][d^1]]=y;
ch[x][d^1]=y;
}
void updata(int x)
{
q[0]=0;
while(1)
{
q[++q[0]]=x;
if(!isr(x)) x=fa[x];
else break;
}
for(int i=q[0];i>=1;i--) pushdown(q[i]);
}
void splay(int x)
{
updata(x);
while(!isr(x))
{
int y=fa[x],z=fa[y];
if(!isr(y))
{
if((x==ch[y][0])^(y==ch[z][0])) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
int y=0;
while(x) splay(x),ch[x][1]=y,y=x,x=fa[x];
}
void link(int x,int y)
{
fa[y]=x,access(x),splay(x),s[x]+=s[y],tag[x]+=s[y];
}
void cut(int x)
{
access(x),splay(x),s[ch[x][0]]-=s[x],tag[ch[x][0]]-=s[x];
fa[ch[x][0]]=0,ch[x][0]=0;
}
}T;
char str[maxn];
struct SAM
{
int pre[maxn],ch[maxn][26],dep[maxn],last,tot;
void add(int x)
{
int p=last,np=++tot;
last=np,dep[np]=dep[p]+1,T.s[np]=1;
for(;p&&!ch[p][x];p=pre[p]) ch[p][x]=np;
if(!p) pre[np]=1,T.link(1,np);
else
{
int q=ch[p][x];
if(dep[q]==dep[p]+1) pre[np]=q,T.link(q,np);
else
{
int nq=++tot;
dep[nq]=dep[p]+1,pre[nq]=pre[q],pre[q]=pre[np]=nq;
T.cut(q),T.link(pre[nq],nq),T.link(nq,q),T.link(nq,np);
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=nq;
}
}
}
int query()
{
int i,p=1;
for(i=p=1;i<=len&&p;i++) p=ch[p][str[i-1]-'A'];
if(!p) return 0;
T.updata(p);
return T.s[p];
}
}S;
void decode()
{
scanf("%s",str),len=strlen(str);
int i,ms=msk;
for(i=0;i<len;i++)
{
ms=(ms*131+i)%len;
swap(str[i],str[ms]);
}
}
int main()
{
scanf("%d",&m);
S.last=S.tot=1;
int i,j;
scanf("%s",str),len=strlen(str);
for(i=1;i<=len;i++) S.add(str[i-1]-'A');
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='A')
{
decode();
for(j=1;j<=len;j++) S.add(str[j-1]-'A');
}
else
{
decode(),ans=S.query(),msk^=ans;
printf("%d\n",ans);
}
}
return 0;
}

【BZOJ2555】SubString 后缀自动机+LCT的更多相关文章

  1. luogu5212/bzoj2555 substring(后缀自动机+动态树)

    对字符串构建一个后缀自动机. 每次查询的就是在转移边上得到节点的parent树中后缀节点数量. 由于强制在线,可以用动态树维护后缀自动机parent树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...

  2. bzoj 2555 SubString —— 后缀自动机+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2555 建立后缀自动机,就可以直接加入新串了: 出现次数就是 Right 集合的大小,需要查询 ...

  3. bzoj 2555: SubString 后缀自动机+LCT

    2555: SubString Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 688  Solved: 235[Submit][Status][Dis ...

  4. bzoj 2555 SubString——后缀自动机+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2555 要维护 right 集合的大小.因为 fa 会变,且 fa 构成一棵树,所以考虑用 L ...

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

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

  6. bzoj2555(后缀自动机+LCT)

    题目描述 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 题解 做法很自然,建出后缀自动机,维护每个节点的right ...

  7. bzoj 2555: SubString【后缀自动机+LCT】

    一直WA--找了半天错的发现居然是解密那里的mask其实是不能动的--传进去的会变,但是真实的那个不会变-- 然后就是后缀自动机,用LCT维护parent树了--注意不能makeroot,因为自动机的 ...

  8. SPOJ1811 LCS - Longest Common Substring(后缀自动机)

    A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the s ...

  9. 51nod 1600 Simple KMP【后缀自动机+LCT】【思维好题】*

    Description 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i&l ...

随机推荐

  1. XP如何安装字体

    1 点击控制面板,选择外观和主题,然后在左侧菜单中选择字体 2 点击文件,安装新字体选择驱动器和文件夹以找到自己下载的字体文件位置(如微软雅黑.ttf)点击确定之后可以安装.

  2. Vue 状态管理 Vuex

    1.概述 Vuex作为插件,管理和维护整个项目的组件状态. 2.安装vuex cnpm i --save vuex 3.vuex使用 github地址:https://github.com/MengF ...

  3. Atitit.编程语言原理---方法重载的实现与设计 调用方法的原理

    Atitit.编程语言原理---方法重载的实现与设计 调用方法的原理 1. 重载包括:普通方法的重载和构造方法的重载 1 1.1. 横向重载”和“纵向重载”1 1.2. 方法签名通过  方法名称,参数 ...

  4. 通过虚拟驱动vivi分析摄像头驱动

    Linux摄像头驱动学习之:(二)通过虚拟驱动vivi分析摄像头驱动 一.通过指令 "strace -o xawtv.log xawtv" 得到以下调用信息: // 1~7都是在v ...

  5. Visual Studio- “无法启动此程序,因为计算机中丢失 xxx.dll尝试重新安装该程序以解决此问题"

    下午使用VS 2013调试程序时,发现弹出了下列的错误弹框: 网上搜索之后发现是缺失了动态链接库(.dll)文件所致,因此只需要把相应的动态链接库文件放置到指定的目录即可. 另:64位系统用户需要注意 ...

  6. python模块学习之logging

    filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中. filemode:文件打开方式,在指定了filename时使用这个 ...

  7. AES中几种加密模式的区别:ECB、CBC、CFB、OFB、CTR

    AES: aes是基于数据块的加密方式,也就是说,每次处理的数据时一块(16字节),当数据不是16字节的倍数时填充,这就是所谓的分组密码(区别于基于比特位的流密码),16字节是分组长度 分组加密的几种 ...

  8. vue 声明响应式属性

    声明响应式属性 由于vue不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值: var vm = new Vue({ data: { // 声明 message ...

  9. 使用httpClient发送get\post请求

    maven依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId&g ...

  10. 八款开源 Android 游戏引擎[转]

    记录一下,以备不时之需~~~~~ 虽然android学了点点,然后现在又没学了(我为啥这么没有恒心呢大哭).以后有时间还是要继续学android的,一定要啊!虽然现在没学android游戏编程,不过还 ...