2555: SubString

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 688  Solved: 235
[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

  5月20日,新加数据一组,今天5月21号。我选时间怎么就选的这么优秀。还对着一堆比我慢的程序调了半天的常数。。。

  第一次做这类维护right集合大小的题目,right集合大小即子树有用节点的数量,有用节点即不是复制出来的节点。

  在昨天以前这个直接暴力维护暴力链加,修改父亲,然而现在就只有LCT了。另外,为啥不全部重测QAQ,不平衡啊。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
using namespace std;
#define MAXN 1210000
int pnt[MAXN],ch[MAXN][],pls[MAXN],val[MAXN];
bool rev[MAXN];
int stack[MAXN],tops=-;
bool is_root(int now)
{
return !pnt[now] || (ch[pnt[now]][]!=now && ch[pnt[now]][]!=now);
}
void update(int){}
void make_reverse(int now)
{
swap(ch[now][],ch[now][]);
rev[now]^=;
}
void make_plus(int now,int v)
{
val[now]+=v;
pls[now]+=v;
}
void down(int now)
{
if (rev[now])
{
make_reverse(ch[now][]);
make_reverse(ch[now][]);
rev[now]=;
}
if (pls[now])
{
make_plus(ch[now][],pls[now]);
make_plus(ch[now][],pls[now]);
pls[now]=;
}
}
void rotate(int now)
{
int p=pnt[now],anc=pnt[p];
int dir=ch[p][]==now;
if (!is_root(p))
ch[anc][ch[anc][]==p]=now;
pnt[now]=anc;
pnt[ch[now][dir]]=p;
ch[p][-dir]=ch[now][dir];
pnt[p]=now;
ch[now][dir]=p;
update(p);
update(now);
} void splay(int now)
{
int x=now;
stack[++tops]=now;
while (!is_root(x))
{
x=pnt[x];
stack[++tops]=x;
}
while(~tops)
down(stack[tops--]);
while (!is_root(now))
{
int p=pnt[now],anc=pnt[p];
if (is_root(p))
rotate(now);
else if ((ch[anc][]==p) == (ch[p][]==now))
rotate(p),rotate(now);
else
rotate(now),rotate(now);
}
}
int access(int now)
{
int son=;
while (now)
{
splay(now);
ch[now][]=son;
update(now);
son=now;
now=pnt[now];
}
return son;
}
bool same_tree(int x,int y)
{
while (pnt[x])x=pnt[x];
while (pnt[y])y=pnt[y];
return x==y;
}
void make_root(int now)
{
make_reverse(access(now));
}
void path_plus(int x,int y,int v)
{
//cout<<"Plus:"<<x<<" "<<y<<endl;
assert(same_tree(x,y));
make_root(x);
make_plus(access(y),v);
}
void link(int x,int y)
{
//cout<<"Link:"<<x<<" "<<y<<endl;
assert(!same_tree(x,y));
make_root(x),access(x);
make_root(y),access(y);
pnt[x]=y;
ch[y][]=x;
}
void cut(int x,int y)
{
//cout<<"Cut:"<<x<<" "<<y<<endl;
assert(same_tree(x,y));
make_root(x);
access(y);
ch[x][]=;
pnt[y]=;
}
char str[MAXN],ss[MAXN];
struct sam_node
{
int nxt[];
int pnt;
int len;
}sam[MAXN];
int topsam=;
int last=;
void Add_sam(char ch)
{
register int p=last;
register int np=++topsam;
sam[np].len=sam[p].len+;
val[np]=;
while (p && !sam[p].nxt[ch-'A'])
{
sam[p].nxt[ch-'A']=np;
p=sam[p].pnt;
}
if (!p)
{
last=np;
sam[np].pnt=;
link(np,sam[np].pnt);
}else
{
register int q=sam[p].nxt[ch-'A'];
if (sam[q].len==sam[p].len+)
{
sam[np].pnt=q;
link(sam[np].pnt,np);
last=np;
}else
{
register int nq=++topsam;
splay(q);
val[nq]=val[q];
sam[nq]=sam[q];
link(sam[nq].pnt,nq);
sam[nq].len=sam[p].len+;
cut(sam[q].pnt,q);
/*ooo*/sam[q].pnt=nq;
link(sam[q].pnt,q);
/*ooo*/sam[np].pnt=nq;
link(sam[np].pnt,np);
while (p && sam[p].nxt[ch-'A']==q)
{
sam[p].nxt[ch-'A']=nq;
p=sam[p].pnt;
}
last=np;
}
}
path_plus(,sam[np].pnt,);
}
char curs[MAXN];int totc=;
/*
void dfs_sam(int now)
{
if (sam[now].flag)
printf("%s\n",curs);
for (int i=0;i<26;i++)
{
if (!sam[now].nxt[i])continue;
curs[totc++]=(char)(i+'A');
dfs_sam(sam[now].nxt[i]);
curs[--totc]='\0';
}
}*/
int find_sam(char *str)
{
int now=;
while (*str)
{
if (!sam[now].nxt[*str-'A'])return ;
assert(sam[now].nxt[*str-'A']);
now=sam[now].nxt[*str-'A'];
str++;
}
make_root(now);
access(now);
return val[now];
}
void Decode(char* str,int len,int mask)
{
for (register int i=;i<len;i++)
{
mask=(mask*+i)%len;
swap(str[i],str[mask]);
}
}
char opt[];
char cc[MAXN];
int main()
{
freopen("input.txt","r",stdin);
int n,m,x,y,z;
scanf("%d\n",&m);
scanf("%s",str);
int l=strlen(str);
for (int i=;i<l;i++)
Add_sam(str[i]);
/*
for (int i=last;i;i=sam[i].pnt)sam[i].flag=true;
dfs_sam(1);
for (int i=0;i<l;i++)find_sam(str+i);*/
int lastans=;
for (int i=;i<m;i++)
{
scanf("%s %s\n",opt,cc);
int t;
t=strlen(cc);
Decode(cc,t,lastans);
if (opt[]=='Q')
{
int now=;
printf("%d\n",t=find_sam(cc));
lastans^=t;
}else
{
int t=strlen(cc);
for (int i=;i<t;i++)
Add_sam(cc[i]);
}
}
}

bzoj 2555: SubString 后缀自动机+LCT的更多相关文章

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

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

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

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

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

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

  4. bzoj 2555 SubString(SAM+LCT)

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

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

    [BZOJ2555]SubString Description 懒得写背景了,给你一个字符串init,要求你支持两个操作         (1):在当前字符串的后面插入一个字符串         (2 ...

  6. bzoj 5408: string 后缀自动机 + LCT

    联赛前练练码力. code: #include <vector> #include <cstdio> #include <cstring> #include < ...

  7. ●BZOJ 2555 SubString

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

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

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

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

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

随机推荐

  1. Atom编辑器入门到精通(六) Markdown支持

    尽管我们使用Atom主要是为了编写代码,不过Atom还支持编辑很多其他格式的文件. 比如Markdown和Asciidoc. 这一章中我们主要学习如何快速方便地编辑Markdown文件.另外在写这篇博 ...

  2. 纯CSS实现三列布局(两边固定,中间自适应)

    看了一些网上的案例,感觉较繁杂,于是,自己整理了一篇来说明这个东西. 也是给我自己复习吧,以前有人问道,我还没答上来呢.== 看代码: html: <div class="top&qu ...

  3. scala学习笔记:match与unapply()

    编写如下代码: object MatchTest { def foo(a : Any) : String = { a match { case 1 => "int:1" ca ...

  4. 仿php的日期函数,asp时间处理函数

    <% '****************************** '时间处理函数 'FormatDate(Str,DateTime) 'Str 字符串,DateTime 时间 '返回类型为字 ...

  5. 如何在ANDROID JNI 的C++中打Log

    http://blog.csdn.net/pkigavin/article/details/8583537 最近在研究Android 2.3.3源代码的C/C++层,需要对代码进行一些调试,但是奇怪的 ...

  6. python 笔记(一)

    1.Python优点 简单,优雅,明确 强大的模块第三方库 易移植 面向对角 可扩展 2.缺点 代码不能加密 执行速度慢 3.变量定义 第一个字母必须是字母表中的大小写,或下划线.不能以数字为开头. ...

  7. Oracle连接配置以及实例的备份和恢复

    背景:一个团队项目开发,不可能每个人都架设自己本地的数据库,大多数情况下是统一用服务器上的数据库,这时候就需要进行远程数据库的连接.而且有时候还需要进行数据库搬迁 ,这时候就需要进行数据库的备份和恢复 ...

  8. VS2013开发Windows服务项目

    这篇随笔里,我将介绍如何用VS2013开发Windows服务项目,实现的功能是定时发送电子邮件. 开发环境:VS2013,SQL Server2008,采用C#语言开发 步骤一:创建Windows服务 ...

  9. OC 将NSString写入本地文件

    最近在公司偶尔遇到一些不经常复现的bug,为了调试,只好把关键值记录到本地文件中,在遇到问题时,调出本地文件查看一下就可以很方便的知道是不是代码逻辑的错误或者问题考虑不够周全了. 废话不多说,流程在代 ...

  10. iOS中 常用的mac终端指令

    1.使用caffeinate阻止Mac运行屏幕保护和睡眠 caffeinate能阻止Mac进入睡眠状态,而且屏幕保护也不会激活.我们最好使用-t为命令加入具体的时间.比如下面的命令可以使Mac一小时内 ...