2434: [Noi2011]阿狸的打字机

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1834  Solved: 1053
[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

 
  这题我很久以前见到过,当时没敢动手,现在学了AC自动机后,果断拿来练手了。
  题意很简单,可以离线。
  这里在建完fail树后须将fail边反向,建成一棵fail树,如果能A到B有条边,那么代表trie树上到A的字符串是到B的字符串的后缀,这时来一遍DFS,记录每一个点的时间戳,即一个时间段,be[i]指i点自己的编号,也指其开始,en[i]指其结束。
  对于一个节点,它在fail树上的子树中,所有节点的fail都直接或间接的连向它,指它是那些的子串,被他们包含,而用时间戳可以迅速知道一个点是否是其子树。
  之后用离线做法处理答案,用bit维护。
 
 #include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=1e5+;
char S[maxn];
int Query[maxn][],ans[maxn],cntQ;
struct A_Cautomation{
int ch[maxn][],fail[maxn],end[maxn],fa[maxn],ID[maxn],cnt,root,cont;
int fir[maxn],nxt[maxn],to[maxn],cot;
int be[maxn],en[maxn],sjc;
void Init()
{
memset(ch,,sizeof(ch));
memset(fail,,sizeof(fail));
memset(end,,sizeof(end));
sjc=cot=cnt=cont=root=;
}
void Insert()
{
scanf("%s",S);
int len=strlen(S),node=root;
for(int i=;i<len;i++)
{
if(S[i]>='a'&&S[i]<='z'){
if(ch[node][S[i]-'`']){
node=ch[node][S[i]-'`'];
}
else{
fa[++cnt]=node;
node=ch[node][S[i]-'`']=cnt;
}
}
else{
if(S[i]=='B'){
node=fa[node];
}
else{
end[node]=++cont;
ID[cont]=node;
}
}
}
}
void Build()
{
queue<int>q;
for(int i=;i<=;i++){
if(ch[root][i]){
fail[ch[root][i]]=root;
q.push(ch[root][i]);
}
else
ch[root][i]=root;
}
while(!q.empty())
{
int node=q.front();q.pop();
for(int i=;i<=;i++){
if(ch[node][i]){
fail[ch[node][i]]=ch[fail[node]][i];
q.push(ch[node][i]);
}
else{
ch[node][i]=ch[fail[node]][i];
}
}
}
} void addedge(int a,int b)
{nxt[++cot]=fir[a];fir[a]=cot;to[cot]=b;} void DFS(int node)
{
be[node]=++sjc;
for(int i=fir[node];i;i=nxt[i])
DFS(to[i]);
en[node]=sjc;
} void BuildTree()
{
for(int i=;i<=cnt;i++)
addedge(fail[i],i); DFS(root);
} int bit[maxn];
void change(int k,int x)
{
while(k<=)
{
bit[k]+=x;
k+=k&(-k);
}
} int Quer(int k)
{
int ret=;
while(k)
{
ret+=bit[k];
k-=k&(-k);
}
return ret;
} void Solve()
{
memset(fir,,sizeof(fir));cot=;
memset(bit,,sizeof(bit));
for(int i=;i<=cntQ;i++)
Query[i][]=ID[Query[i][]],
Query[i][]=ID[Query[i][]],
addedge(Query[i][],Query[i][]); int len=strlen(S),node=root;
for(int i=;i<len;i++)
{
if(S[i]>='a'&&S[i]<='z'){
node=ch[node][S[i]-'`'];
change(be[node],);
}
else{
if(S[i]=='B'){
change(be[node],-);
node=fa[node];
}
else{
for(int i=fir[node];i;i=nxt[i]){
ans[i]=Quer(en[to[i]])-Quer(be[to[i]]-);
}
}
}
} for(int i=;i<=cntQ;i++)
printf("%d\n",ans[i]);
}
}AC; int main()
{
AC.Init();
AC.Insert();
AC.Build();
AC.BuildTree(); int Q;
scanf("%d",&Q);
while(Q--)
scanf("%d%d",&Query[cntQ][],&Query[++cntQ][]); AC.Solve();
return ;
}

AC自动机:BZOJ 2434 阿狸的打字机的更多相关文章

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

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

  2. BZOJ 2434 阿狸的打字机

    http://www.lydsy.com/JudgeOnline/problem.php?id=2434 思路:建立fail树,并找出dfs序,那剩下要做的就是每次找到一个串的位置,然后询问它的区间里 ...

  3. [NOI 2011][BZOJ 2434] 阿狸的打字机

    传送门 AC自动机 + 树状数组 建成AC自动机后,设end[i]为第i个串的末尾在Trie树上的节点. 可以发现,对于一个询问(x,y),ans等于Trie树上root到end[y]这条链上fail ...

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

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

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

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

  6. BZOJ 2434 阿狸的打字机(fail树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2434 题意:阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28 ...

  7. bzoj 2434: 阿狸的打字机 fail树+离线树状数组

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 首先我们可以发现这个打字的过程本身就是在Trie上滚来滚去的过程 所以我们 ...

  8. bzoj 2434 阿狸的打字机 fail树的性质

    如果a串是另b串的后缀,那么在trie图上沿着b的fail指针走一定可以走到a串. 而a串在b串里出现多少次就是它是多少个前缀的后缀. 所以把fail边反向建树维护个dfs序就行了. 并不是很难... ...

  9. AC自动机-算法详解

    What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...

随机推荐

  1. hdu 5073 Galaxy

    题意是给定n个点,让求找到一个点p使得sigma( (a[i] - p) ^ 2 ) 最小,其中a[i]表示第i个点的位置.其中有k个点不用算. 思路:发现这道题其实就是求n-k个点方差. 那么推一下 ...

  2. Css实现透明效果,兼容IE8

    Css实现透明效果,兼容IE8 >>>>>>>>>>>>>>>>>>>>> ...

  3. ASP.NET 打包下载文件

    使用的类库为:ICSharpCode.SharpZipLib.dll 一种是打包整个文件夹,另一种是打包指定的多个文件,大同小异: using ICSharpCode.SharpZipLib.Zip; ...

  4. (转)resize扩展

    jquery 默认的resize只能监听到浏览器窗口大小的改变,但我们在实际使用过程中有可能还需要监听某个div或其它标签的大小改变来执行相应的处理,如果使用默认的resize就无能为力了.怎么办呢, ...

  5. CSS3条件判断——@supports/window.CSS.supports()(转)

    CSS3条件判断,听起来"不明觉厉",如果你对CSS稍为熟悉一点的话,你会发现CSS中的"@media"就是条件判断之一.是的,在CSS3的条件判断规范文档中包 ...

  6. Asp.net Mvc4 基于Authorize实现的模块访问权限

    在MVC中,我们可以通过在action或者controller上设置Authorize[Role="xxx"] 的方式来设置用户对action的访问权限.显然,这样并不能满足我们的 ...

  7. 关于mssql数据库锁和事务隔离级别

    事务隔离级别有4种,这4种级别只是对于读操作,也就是select有不同程度的支持, 读未提交:不会对事务里读出来的数据附加任何锁 读已提交:会对事务里读出来的数据附加共享锁,读完就释放共享锁,其他事务 ...

  8. head标签

    1.head标签中有个<meta>,,个人理解知识,可以设置页面字符集,文本格式,还可以加一些注释,例如如下所示

  9. gulp安装

    1. npm install gulp -g    全局安装  npm install gulp --save-dev  安装文件内,纪录于package.json     接著安装插件,完成下列任务 ...

  10. PHP-HTML重要知识点笔记

    1.用frameset.frame和iframe还实现多窗口 2.在图片上利用映射距离usemap来实现按钮跳转.------第8尾集 3.表单必须要有name和value,因为抓包的时候,可发现必须 ...