2555: SubString

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 1936  Solved: 551
[Submit][Status][Discuss]

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

新加数据一组--2015.05.20

Source

Ctsc模拟赛By 洁妹

Solution

论文里最难搞的一道题,谢谢 abclzr队长 的帮助。

一个串在模板串中的出现次数显然就是$|Right(s)|$,然后这个的求法是$Parent$树的子树中的叶子节点个数。

暴力的查询是单次$O(N)$,总体$O(N^{2})$的,所以要利用数据结构LCT维护,实现查询$O(logN)$。

在构建SAM的同时要在LCT上进行相应的Link/Cut操作,在Cut的时候,需要将其贡献减去。

样例有点弱,自己搞了个测试点:

ABABA

QUERY AB
QUERY A
ADD BAB
QUERY AB
QUERY A

Input


Output

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 1200010
char S[MAXN];
int N,Q,M,ans,Mask;
inline void read()
{
string str=S+1;
int mask=Mask;
for (int i=0; i<str.length(); i++)
{
mask=(mask*131+i)%str.length();
swap(str[i],str[mask]);
}
for (int i=0,tot=0; i<str.length(); i++) S[++tot]=str[i];
}
namespace LCT
{
int fa[MAXN],ch[MAXN][2],val[MAXN],tag[MAXN];
inline bool is_root(int x) {return !fa[x] || ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;}
inline void Add(int x,int v) {if (!x) return; val[x]+=v,tag[x]+=v;}
inline void Pushdown(int x) {if (tag[x]) Add(ch[x][0],tag[x]),Add(ch[x][1],tag[x]),tag[x]=0;}
inline void Rotate(int x)
{
int y=fa[x],w=ch[y][1]==x,z=fa[y];
ch[y][w]=ch[x][w^1];
if (ch[x][w^1]) fa[ch[x][w^1]]=y;
if (ch[z][0]==y) ch[z][0]=x; else if (ch[z][1]==y) ch[z][1]=x;
fa[x]=fa[y]; fa[y]=x; ch[x][w^1]=y;
}
int stack[MAXN];
inline void Splay(int x)
{
int top=0,t=x,y; stack[++top]=x;
while (!is_root(t)) stack[++top]=t=fa[t];
while (top) Pushdown(stack[top--]);
while (!is_root(x))
{
y=fa[x];
if (!is_root(y))
if ((ch[fa[y]][0]==y)^(ch[y][0]==x)) Rotate(x);
else Rotate(y);
Rotate(x);
}
}
inline void Access(int x) {for (int y=0; x; y=x,x=fa[x]) Splay(x),ch[x][1]=y;}
inline void Link(int x,int y) {fa[x]=y; Access(y); Splay(y); Add(y,val[x]);}
inline void Cut(int x) {Access(x); Splay(x); Add(ch[x][0],-val[x]); fa[ch[x][0]]=0,ch[x][0]=0;}
}using namespace LCT;
namespace SAM
{
int son[MAXN][27],len[MAXN],par[MAXN];
int root,last,sz;
inline void Init() {root=last=sz=1;}
inline void Extend(int c)
{
int cur=++sz,p=last;
len[cur]=len[p]+1; LCT::val[cur]=1;
while (p && !son[p][c]) son[p][c]=cur,p=par[p];
if (!p) par[cur]=root,LCT::Link(cur,root);
else
{
int q=son[p][c];
if (len[p]+1==len[q]) par[cur]=q,LCT::Link(cur,q);
else
{
int nq=++sz;
memcpy(son[nq],son[q],sizeof(son[nq]));
len[nq]=len[p]+1,par[nq]=par[q]; LCT::Link(nq,par[nq]);
while (p && son[p][c]==q) son[p][c]=nq,p=par[p];
par[cur]=par[q]=nq;
LCT::Cut(q); LCT::Link(cur,nq); LCT::Link(q,nq);
}
}
last=cur;
}
inline void Build() {Init(); for (int i=1; i<=N; i++) Extend(S[i]-'A'+1);}
inline void Insert()
{
read(); M=strlen(S+1);
for (int i=1; i<=M; i++) Extend(S[i]-'A'+1);
}
inline int Query()
{
read(); M=strlen(S+1);
int now=root;
for (int i=1; i<=M; i++)
if (!son[now][S[i]-'A'+1]) return 0;
else now=son[now][S[i]-'A'+1];
LCT::Splay(now);
return val[now];
}
}using namespace SAM;
int main()
{
scanf("%d",&Q);
scanf("%s",S+1); N=strlen(S+1);
SAM::Build();
while (Q--)
{
char opt[10];
scanf("%s%s",opt+1,S+1);
switch (opt[1])
{
case 'A' : SAM::Insert(); break;
case 'Q' : printf("%d\n",ans=SAM::Query()); Mask^=ans; break;
}
// for (int i=1; i<=sz; i++) printf("%d %d %d %d\n",i,ch[i][0],ch[i][1],val[i]);
}
return 0;
}

  

太久没看LCT了,出现大片遗忘,背了个模板都能弄错,其实应该先复习一下LCT再写这道题的。

【BZOJ-2555】SubString 后缀自动机 + LinkCutTree的更多相关文章

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

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

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

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

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

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

  4. BZOJ 2555: SubString 后缀自动机_LCT

    很水的一道题,就是有些细节没注意到. 比如说将调试信息误以为是最终结果而多调了20分钟QAQ ..... 我们注意到,每新加一个节点,改变的是该节点沿着 Parent 走一直走到根节点. 对应的,在 ...

  5. 字符串(LCT,后缀自动机):BZOJ 2555 SubString

    2555: SubString Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1620  Solved: 471 Description 懒得写背景了 ...

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

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

  7. ●BZOJ 2555 SubString

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2555题解: 后缀自动机+LCT 不难发现,对于输入的询问串,在自动机里trans后的到的状态 ...

  8. bzoj 2555 SubString(SAM+LCT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2555 [题意] 给定一个字符串,可以随时插入字符串,提供查询s在其中作为连续子串的出现 ...

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

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

随机推荐

  1. 物联网框架SuperIO 2.2.9和ServerSuperIO 2.1同时更新,更适用于类似西门子s7-200发送多次数据,才能读取数据的情况

    一.解决方案 二.更新内容 1.修改IRunDevice接口,把void Send(io,bytes)改成int Send(io,bytes).2.修改网络控制器,发送数据不直接使用IO实例,改为使用 ...

  2. java 的持久化和序列化的简单理解

    1.对象的持久化(Persistence) 对象持久化就是让对象的生存期超越使用对象的程序的运行期.将对象存储在可持久保存的存储介质上,在实际应用中,运用相应的对象持久化框架,将业务数据以对象的方式保 ...

  3. 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.0.1

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...

  4. java web学习总结(二十四) -------------------Servlet文件上传和下载的实现

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  5. glibc 各版本发布时间以及内核默认glibc版本

    最近有些软件要求glibc 2.14+,centos 6.x自带的版本是2.12的,特查了下glibc 各版本发布时间以及与对应的内核,如下: Complete glibc release histo ...

  6. 关于css3的背景渐变

    关于css3的渐变,目前各大浏览器还未做到很好的支持,所以需要在我们使用时加上各大浏览器前缀. -moz-:使用Mozilla内核的浏览器(Firefox浏览器) -webkit-:使用Webkit内 ...

  7. JavaScript 函数表达式

    JavaScript中创建函数主要有两种方法:函数声明和函数表达式.这两种方式都有不同的适用场景.这篇笔记主要关注的是函数表达式的几大特点以及它的使用场景,下面一一描述. 主要特点 可选的函数名称 函 ...

  8. Dynamics CRM 2015-超大Solution导入问题

    我们在将比较大的solution导入CRM的时候,经常会遇到超时的问题,这是因为CRM的本身的优化限制导致的,那么如何解决呢? 官方已经有了解决方案了. 在浏览完两种解决方法之后,我们要知道的是: 1 ...

  9. css选择器的使用详解

    -.css选择器的分类: 二.常用选择器详解: 1.标签选择器: 语法: 标签名 { 属性:属性值; } 代码示例: h1 { color: #ccc; font-size: 28px; } 2.类选 ...

  10. Oracle学习笔记五 SQL命令(三):Group by、排序、连接查询、子查询、分页

    GROUP BY和HAVING子句 GROUP BY子句 用于将信息划分为更小的组每一组行返回针对该组的单个结果 --统计每个部门的人数: Select count(*) from emp group ...