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. Spring 4.1+ 的 JSONP使用

    如今的巨石应用已经越来越不行了,很多互联网在后期都会在用分布式的架构 那么在页面上不同的服务调用不同域名下的json是有问题的 (跨域:不同域名,相同域名但是不同端口) JavaScript规范中提到 ...

  2. 如何查看windows xp系统的位数?

    1.右击“我的电脑”->属性,可以看到.2.运行dxdiag,在操作系统一行可以看到.3.运行cmd,输入systeminfo,在系统类型一栏可以看到.--简单4.使用一些检测软件也可以看,像鲁 ...

  3. Maven简介与简单使用

    Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具. Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具.由于 Maven 的缺省构建 ...

  4. Nuget如何管理本地的包

    1.在nuget中创建一个本地的程序包源

  5. JqueryMobile入门基础附源码下载

    最近要做一个手机版的网站,所以就了解了一点JqueryMObile,下面是我整理的笔记,现在分享给大家,希望朋友们喜欢,先给个首页看看吧!!! 一.JqueryMobile基本页面结构 <!DO ...

  6. select、poll、epoll程序实例

    三个函数的基本用法如下: select 创建 fd_set rset , allset; FD_ZERO(&allset); FD_SET(listenfd, &allset); 监听 ...

  7. ASP.NET中进行消息处理(MSMQ) 三

    在本文的前两篇文章里对MSMQ的相关知识点进行了介绍,很多阅读过这前两篇文章的朋友都曾问到过这样一些问题:  1.如何把MSMQ应用到实际的项目中去呢?  2.可不可以介绍一个实际的应用实例?  3. ...

  8. InfluxDb系列:几个关键概念(主要是和关系数据库做对比)

    https://docs.influxdata.com/influxdb/v0.9/concepts/key_concepts/  #,measurement,就相当于关系数据库中的table,他就是 ...

  9. [CareerCup] 8.4 Parking Lot 停车场问题

    8.4 Design a parking lot using object-oriented principles. LintCode上的原题,请参见我的另一篇博客Parking Lot 停车场问题. ...

  10. swift语言的学习笔记

    swift参考了OC,Rust,Haskell,Ruby,Python,C#等语言的特性.首先,学习这门语言是速学的,我不想浪费太多时间在笔记这门语言和其他语言的哪里不同,特性你自己亲自实践就知道了. ...