2434: [Noi2011]阿狸的打字机

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 2022  Solved: 1158
[Submit][Status][Discuss]

Description

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。
经阿狸研究发现,这个打字机是这样工作的:
l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

Input

输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。
第二行包含一个整数m,表示询问个数。
接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

Output

输出m行,其中第i行包含一个整数,表示第i个询问的答案。

Sample Input

aPaPBbP
3
1 2
1 3
2 3

Sample Output

2
1
0

HINT

1<=N<=10^5

1<=M<=10^5
输入总长<=10^5

Source

Trie

Solution

好题,值得多次练习

AC自动机无疑,建出Fail指针的同时,根据Fail指针反向建树,即Fail树

以x为根的子树沿着fail指针倒着走能找到多少个y路径上的点就说明x在y上出现过几次。

那么利用DFS,求出每个点的时间戳(即每个节点最先到达的时间和最后到达时间),那么发现,对于子树,是一种类似前缀和的存在

那么用线段树或者树状数组来维护一下

值得注意的几点:(皆为亲身经历)

首先在建Trie树的过程中,应该考虑直接对整个操作串进行处理,不断分离去插入会TLE

对于操作串的长度,不应该直接在for循环中使用strlen(),应该先记录下来len=strlen()后循环中直接用len,否则更TLE

不要企图在线处理,应该优先考虑离线处理,否则也会出现奇怪的错误

对于Fail树,应该建单向边,并非双向边,否则可能出现错误

数组要开的够大,题目中10^5,开到10^5+100,Tyvj秒A,CodeVS秒A,BZOJ狂WA不止,怒开2×10^5秒A...不知所措

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int read()
{
int x=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x;
}
#define N 210000
int son[N][],fail[N],q[N],sz,t,len,m,ans[N],fa[N],loc[N];
char s[N],opt[N];
struct data{int to,next;}edge[N],ask[N];
int cn,cnt,head[N],heada[N],lastq[N];
void addedge(int u,int v)
{cnt++;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;}
void addask(int x,int y,int z)
{ask[z].next=heada[y];heada[y]=z;ask[z].to=x;}
int tree[N];
inline int lowbit(int x){return x&(-x);}
void change(int loc,int val)
{
for (int i=loc; i<=t; i+=lowbit(i))
tree[i]+=val;
}
int query(int loc)
{
int ans=;
for (int i=loc; i>=; i-=lowbit(i))
ans+=tree[i];
return ans;
}
int L[N],R[N];
void dfs(int x)
{
L[x]=++t;
for (int i=head[x]; i; i=edge[i].next)
dfs(edge[i].to);
R[x]=++t;
//printf("L=%d R=%d\n",L[x],R[x]);
}
void clear()
{sz=;for (int i=; i<; i++) son[][i]=;}
void buildTrie()
{
int x=,id=;
for (int i=; i<len; i++)
if (opt[i]=='P') loc[++id]=x;
else if (opt[i]=='B') x=fa[x];
else
{
if (!son[x][opt[i]-'a'])
son[x][opt[i]-'a']=++sz,fa[sz]=x;
x=son[x][opt[i]-'a'];
}
}
void buildFail()
{
int he=,ta=; q[]=; fail[]=;
while (he<ta)
{
int now=q[he++];
for (int i=; i<; i++)
{
if (!son[now][i]) continue;
int ff=fail[now];
while (!son[ff][i]) ff=fail[ff];
fail[son[now][i]]=son[ff][i];
q[ta++]=son[now][i];
}
}
for (int i=; i<=sz; i++)
addedge(fail[i],i);
}
void work()
{
int now=,id=;
change(L[],);
for (int i=; i<len; i++)
if (opt[i]=='P')
{
id++;
for (int j=heada[id]; j; j=ask[j].next)
ans[j]=query(R[loc[ask[j].to]])-query(L[loc[ask[j].to]]-);
}
else if (opt[i]=='B') change(L[now],-),now=fa[now];
else now=son[now][opt[i]-'a'],change(L[now],);
}
//ACMachine
int main()
{
clear();
scanf("%s",opt); len=strlen(opt);
buildTrie(); buildFail();
m=read();
for (int x,y,i=; i<=m; i++)
x=read(),y=read(),addask(x,y,i);
dfs(); work();
for (int i=; i<=m; i++)
printf("%d\n",ans[i]);
return ;
}

BZOJ数组大小被坑艰辛史

【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组的更多相关文章

  1. BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)

    题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...

  2. BZOJ 2434 阿狸的打字机 | AC自动机

    题目戳这里 AC自动机上有神奇的东西叫做fail指针--所有fail指针连起来恰好构成一棵以1为根的树! 而这道题问x在y中出现过多少次,就是问Trie树上根到y的结束节点的路径上有多少节点能通过跳f ...

  3. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  4. BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  5. bzoj 2434 阿狸的打字机 - Aho-Corasick自动机 - 树状数组

    题目传送门 传送站I 传送站II 题目大意 阿狸有一个打字机,它有3种键: 向缓冲区追加小写字母 P:打印当前缓冲区(缓冲区不变) B:删除缓冲区中最后一个字符 然后多次询问第$x$个被打印出来的串在 ...

  6. AC自动机fail树上dfs序建线段树+动态memset清空

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...

  7. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  8. BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...

  9. BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)

    Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4140  Solved: 2276[Submit][Status][Discuss] Descript ...

随机推荐

  1. SSH框架总结(框架分析+环境搭建+实例源码下载) 《转》

    这篇文章比较易懂,易理解: 首先,SSH不是一个框架,而是多个框架(struts+spring+hibernate)的集成,是目前较流行的一种Web应用程序开源集成框架,用于构建灵活.易于扩展的多层W ...

  2. 我发现:在StackOverflow上拯救歪果仁十分有意思!

    菊长:火星特工们!今天是周五了,大家有什么提议? BeJavaGod:报告菊长!我发现,在StackOverflow上拯救歪果仁十分有意思! 噗哈哈,时不时遇到问题会使用到StackOverflow, ...

  3. 学员信息录入(StuInfoManager) 用分层实现(既MySchool后的一个案例)

    数据库 数据表名 Student 中文表名 学员信息表 字段显示 字段名 数据类型 字段大小 备注和说明 编号 stu_id int 主键,自增1 学生姓名 stu_name varchar 50 不 ...

  4. YII获取刚插入数据的id主键

    单条数据时model->attributes['id']; 循环插入时使用 Yii::app()->db->getLastInsertID() 获取 循环插入时需要每次插入后重置 m ...

  5. Java NIO 概述

    Channel 和 Buffer 标准的Java IO编程接口是面向字节流和字符流的 而 NIO 是面向通道和缓冲区的 数据总是从通道中读到Buffer中,或者从Buffer写入通道中 NIO可以理解 ...

  6. Content Factory:辅助 MonoGame 游戏开发

    Content Factory 是一款辅助 MonoGame 游戏开发的工具.它提供素材管理的多项功能,包括编译素材.编辑自定义数据等,并能同时应用多个游戏平台. 项目设置 选择要创建游戏项目的平台, ...

  7. navigator.sendBeancon方法简介

    之所以介绍这个还在草案中的方法,是源于最近新做的一个活动.该活动有个需求,就是用户离开该页面的某个时间段之后,发个请求给该用户送券.后来是通过setTimeout来做的,用户离开该页面,该页面进入后台 ...

  8. Win7上防火墙开放FTP服务以及ping解决方案(zz)

    1.windows 防火墙开放ftp服务 The following 4 steps will allow both non-secure and SSL FTP traffic through fi ...

  9. Activiti系列: 如何添加自定义表单引擎

    这个功能挺有意思的,有了它,就可以不适用html的方式来展示表单了,比如可以用swing对象了 class MyFormEngine implements FormEngine {     @over ...

  10. Linux常用的基本命令

    man命令:查看帮助信息                       格式:man  需要查看的命令 date命令:显示时间                            格式:# date ...