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用来在一篇文章中匹配一个模式串:但 ...
随机推荐
- shell脚本学习之case例子
case和select结构在技术上说并不是循环, 因为它们并不对可执行代码块进行迭代. 但是和循环相似的是, 它们也依靠在代码块顶部或底部的条件判断来决定程序的分支. 在代码块中控制程序分支 ca ...
- html 5的localstorag
随着我们硬件技术的发展,浏览器本身的功能也愈发的完善,从之前的cookie到现在的本地缓存机制,再到web storage,在之前html4 的时候使用cookie具有一些明显的局限,如大小限制,co ...
- java_设计模式_适配器模式_Adapter Pattern(2016-08-09)
概念 将一个接口转换成客户希望的另外一个接口.(该模式使得原本不兼容的类可以一起工作). UML图 适配器模式有类的适配器模式和对象的适配器模式两种不同的形式. (1)对象的适配器模式结构图 (2)类 ...
- C++前置++与后置++的区别与重载
++属于单目运算符,前置与后置的实现代码不一样,下面以整数自增为例: // 前置++,返回自增后的值,且返回的是一个左值 int& operator++(){ *this += 1; retu ...
- opencv 常用函数介绍
××××××××××××××××××××××××××××××××××××××× CvScalar imgmean,imgstd; double imgmax,imgmin; cvAvgSdv(img, ...
- 【POJ1568】【极大极小搜索+alpha-beta剪枝】Find the Winning Move
Description 4x4 tic-tac-toe is played on a board with four rows (numbered 0 to 3 from top to bottom) ...
- winform 窗体大小变化时,如何设置使控件一起按照比例变大
public Form() { InitializeComponent(); + ; float[] factor = new float[count]; ; factor[i++] = Size.W ...
- angularjs 实现排序功能
实现公式:{{orderBy_expression | orderBy:expression:reverse}} Example <script> var app=angular.modu ...
- android的padding和margin的区别
android:padding和android:layout_margin的区别:padding是站在父view的角度描述问题,它规定它里面的内容必须与这个父view边界的距离. margin则是站在 ...
- 最新选择Godaddy主机方案美国数据中心教程指导
随着Godaddy官方管理层的变动之后,主营重心已经从当初的域名开始转向到域名和主机产品上.这点我们从其发布域名优惠信息的频率也可以看到,而且我们可以看到常年的主机半价优惠,以及针对主机销售年付方案赠 ...