BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的:
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。
经阿狸研究发现,这个打字机是这样工作的:
- 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
- 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
- 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
- 把AC自动机的结点作为树结点,将fail指针的方向取反设为树边,这样除了AC自动机头结点外每个结点都有且仅有一条进入它的边,这样就得到一棵叫fail树的树。
- 在AC自动机中如果y的fail指针指向x,可知x表示的字符串前缀是y结点表示的字符串前缀的后缀;因此可以知道在fail树中x为根的子树的所有结点表示的字符串前缀都包含x结点所表示的字符串前缀。
- 对于,询问一个字符串x在另一个字符串y出现了多少次,就可以这样:在fail树中标记字符串y的所有前缀结点,然后看x为根的子树有多少个被标记结点就是答案,这个可以用DFS序+线段树实现。
- 而对于这题的具体实现:
- 首先可以顺着输入的字符串序列B往父亲走,P标记这样建立AC自动机
- 然后把查询离线处理,用邻接表记录每一组查询<x,y>中每个y有哪几个x
- 最后再顺着输入的字符串序列,遇到B和小写字符更新线段树,遇到P去查询出当前y的所有x的答案
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXN 111111 struct Edge{
int v,next;
}edge[MAXN];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].v=v; edge[NE].next=head[u];
head[u]=NE++;
} int tn,ch[MAXN][],fa[MAXN],flag[MAXN],fail[MAXN];
int belong[MAXN],bn,rbelong[MAXN];
char str[];
void insert(){
int x=;
for(int i=; str[i]; ++i){
if(str[i]=='B'){
x=fa[x];
}else if(str[i]=='P'){
flag[x]=;
belong[x]=++bn;
rbelong[bn]=x;
}else{
int y=str[i]-'a';
if(ch[x][y]==) ch[x][y]=++tn,fa[ch[x][y]]=x;
x=ch[x][y];
}
}
}
void getfail(){
queue<int> que;
for(int i=; i<; ++i){
if(ch[][i]){
que.push(ch[][i]);
addEdge(,ch[][i]);
}
}
while(!que.empty()){
int x=que.front(); que.pop();
for(int i=; i<; ++i){
if(ch[x][i]){
que.push(ch[x][i]);
fail[ch[x][i]]=ch[fail[x]][i];
addEdge(fail[ch[x][i]],ch[x][i]);
}else ch[x][i]=ch[fail[x]][i];
}
}
} int dfn,l[MAXN],r[MAXN],par[MAXN];
void dfs(int u){
l[u]=++dfn;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
par[v]=u;
dfs(v);
}
r[u]=dfn;
} int tree[MAXN<<],N,x,y;
void update(int i,int j,int k){
if(i==j){
tree[k]+=y;
return;
}
int mid=i+j>>;
if(x<=mid) update(i,mid,k<<);
else update(mid+,j,k<<|);
tree[k]=tree[k<<]+tree[k<<|];
}
int query(int i,int j,int k){
if(x<=i && j<=y){
return tree[k];
}
int mid=i+j>>,res=;
if(x<=mid) res+=query(i,mid,k<<);
if(y>mid) res+=query(mid+,j,k<<|);
return res;
} struct Query{
int x,y,ans,next;
}que[MAXN];
int qhead[MAXN],qNE,order[MAXN];
void addQuery(int x,int y){
que[qNE].x=x; que[qNE].y=y; que[qNE].next=qhead[y];
qhead[y]=qNE++;
} void doit(){
int now=;
for(int i=; str[i]; ++i){
if(str[i]=='B'){
x=l[now]; y=-;
update(,N,);
now=fa[now];
}else if(str[i]=='P'){
for(int j=qhead[belong[now]]; j!=-; j=que[j].next){
x=l[rbelong[que[j].x]]; y=r[rbelong[que[j].x]];
que[j].ans=query(,N,);
}
}else{
now=ch[now][str[i]-'a'];
x=l[now]; y=;
update(,N,);
}
}
}
int main(){
scanf("%s",str);
insert();
memset(head,-,sizeof(head));
getfail();
dfs();
for(N=; N<dfn; N<<=);
memset(qhead,-,sizeof(qhead));
int m,a,b;
scanf("%d",&m);
for(int i=; i<m; ++i){
scanf("%d%d",&a,&b);
order[i]=qNE;
addQuery(a,b);
}
doit();
for(int i=; i<m; ++i){
printf("%d\n",que[order[i]].ans);
}
return ;
}
BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)的更多相关文章
- BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组
题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2022 Solved: 1158[Submit][Sta ...
- BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4140 Solved: 2276[Submit][Status][Discuss] Descript ...
- [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...
- BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
随机推荐
- 点击按钮对两个div的隐藏与显示进行切换
HTML: <button type="button" id="showHidden">点击切换div的隐藏与显示</button> ...
- nyoj744(位运算)
题目:http://acm.nyist.net/JudgeOnline/problem.php?pid=744 思路:a^b可以得到a~b间任意两个数异或运算的长度的最大值,设为n,答案为:pow(2 ...
- [译] 用 Swift 创建自定义的键盘
本文翻译自 How to make a custom keyboard in iOS 8 using Swift 我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一 ...
- candence 笔记总结
1.解决candece 启动后提示找不到licence文件的错误: candece的安装就不说了,按照破解步骤一步一步来就行了,但是装完后发现每次启动都会报错 "OrCAD Capture ...
- Android画面显示原理
转自: http://blog.csdn.net/luoshengyang/article/details/7691321/ http://blog.chinaunix.net/uid-1675954 ...
- Python无类再理解--metaclass,type
上次理解过一次,时间久了,就忘了.. 再学习一次.. http://blog.jobbole.com/21351/ ======================= 但是,Python中的类还远不止如此 ...
- 攻城狮在路上(叁)Linux(二十七)--- 压缩与打包之常见的压缩命令
前面讲到,linux中的后缀名没有特殊的意义,一般是作为不同文件类型的标识而已.下面是与打包.压缩相关的后缀名介绍: *.z:compress程序压缩文件 *.gz:gzip程序压缩文件 *.bz2: ...
- 攻城狮在路上(叁)Linux(十七)--- linux磁盘与文件管理概述
一.复习知识点: 1.扇区是最小的物理存储单位,大小为512bytes. 2.扇区组成一个圆,成为柱面,柱面是分区的最小单位. 3.第一个扇区很重要,因为包含了MBR(446字节)和分区表(64字节) ...
- 攻城狮在路上(贰) Spring(二)--- Spring IoC概念介绍
一.IoC的概念: IoC(控制反转)是Spring容器的核心.另一种解释是DI(依赖注入),即让调用类对某一个接口的依赖关系由第三方注入,以移除调用类对某一个接口实现类的一览. 定义如此,由此可见, ...
- hdu 4291 2012成都赛区网络赛 矩阵快速幂 ***
分析:假设g(g(g(n)))=g(x),x可能非常大,但是由于mod 10^9+7,所以可以求出x的循环节 求出x的循环节后,假设g(g(g(n)))=g(x)=g(g(y)),即x=g(y),y也 ...