AC自动机:BZOJ 2434 阿狸的打字机
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
3
1 2
1 3
2 3
Sample Output
1
0
HINT
1<=N<=10^5
1<=M<=10^5
输入总长<=10^5
#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 阿狸的打字机的更多相关文章
- BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)
题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...
- BZOJ 2434 阿狸的打字机
http://www.lydsy.com/JudgeOnline/problem.php?id=2434 思路:建立fail树,并找出dfs序,那剩下要做的就是每次找到一个串的位置,然后询问它的区间里 ...
- [NOI 2011][BZOJ 2434] 阿狸的打字机
传送门 AC自动机 + 树状数组 建成AC自动机后,设end[i]为第i个串的末尾在Trie树上的节点. 可以发现,对于一个询问(x,y),ans等于Trie树上root到end[y]这条链上fail ...
- BZOJ 2434 阿狸的打字机 | AC自动机
题目戳这里 AC自动机上有神奇的东西叫做fail指针--所有fail指针连起来恰好构成一棵以1为根的树! 而这道题问x在y中出现过多少次,就是问Trie树上根到y的结束节点的路径上有多少节点能通过跳f ...
- bzoj 2434 阿狸的打字机 - Aho-Corasick自动机 - 树状数组
题目传送门 传送站I 传送站II 题目大意 阿狸有一个打字机,它有3种键: 向缓冲区追加小写字母 P:打印当前缓冲区(缓冲区不变) B:删除缓冲区中最后一个字符 然后多次询问第$x$个被打印出来的串在 ...
- BZOJ 2434 阿狸的打字机(fail树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2434 题意:阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28 ...
- bzoj 2434: 阿狸的打字机 fail树+离线树状数组
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 首先我们可以发现这个打字的过程本身就是在Trie上滚来滚去的过程 所以我们 ...
- bzoj 2434 阿狸的打字机 fail树的性质
如果a串是另b串的后缀,那么在trie图上沿着b的fail指针走一定可以走到a串. 而a串在b串里出现多少次就是它是多少个前缀的后缀. 所以把fail边反向建树维护个dfs序就行了. 并不是很难... ...
- AC自动机-算法详解
What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...
随机推荐
- 导出到excel
/// <summary> /// 导出 /// </summary> /// <param name="table">数据表</para ...
- Store update, insert, or delete statement affected an unexpected number of rows ({0}).
问题描述 Store update, insert, or delete statement affected an unexpected number of rows ({0}). Entities ...
- C#重载重写
overload:重载指的是同一个类中有两个或多个名字相同但是参数不同的方法,(注:返回值不能区别函数是否重载),重载没有关键字.override:过载也称重写是指子类对父类中虚函数或抽象函数的“覆盖 ...
- retain two decimal digits.
package kju.o; import static kju.print.Printer.*; import java.text.*; class MathDemo { public static ...
- 1 加到 100 的 时间复杂度 C#.
//1 加到 100 的 时间复杂度: ; ; ; i <= n; i++){ sum += i; } T() = ; //Initialize 'n'. T() = ; //Initializ ...
- acl操作记录
官方文档内容: 1.CREATE_ACL Procedure创建ACL Note: This procedure is deprecated in Oracle Database 12c. While ...
- ZendStudio快捷键
Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复制当前行到上一行(复制增加)Alt+↓ 当前 ...
- DataSet与DataTable基本用法
http://files.cnblogs.com/files/monkeyZhong/DataSetExample.rar 在设计数据库操作或者XML操作等表格数据时,我们难免要跟DataSet和Da ...
- What is SaaS?
SaaS, or Software as a Service, describes any cloud service where consumers are able to access softw ...
- JavaScript_变量的自动转换和语句
JS自动类型转换 var a = 1; var b = true; "==" 表示 可以自动类型转换,比较的是数值 "===" 表示可以自动类型转换,先比较数值 ...