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序+树状 ...
随机推荐
- 蜥蜴(bzoj 1066)
Description 在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平 ...
- NYOJ之茵茵的第一课
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAtQAAAJ/CAIAAADXlNOKAAAgAElEQVR4nO3dsVLjOsMG4P8m6LkQ2u
- js函数的几个特殊点
在ECMAScript中,Function(函数)类型实际上是对象.每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法.由于函数是对象,因此函数名实际上也是一个指向函数对象 ...
- Android Tab -- 使用ViewPager、PagerAdapter来实现
原文地址:http://blog.csdn.net/crazy1235/article/details/42678877 效果:滑动切换,自动切换. 代码:https://github.com/ldb ...
- xdg-open filename 以相应的程序 打开文件
[root@ok network-scripts]# xdg-open ifcfg-eth0
- eclipse使用tips-Toggle Mark Occurrences 颜色更改
Toggle Mark Occurrences这个功能非常好用,能把选中的方法/变量在本类中全部出现的地方高亮显示,是一个非常实用的功能.但是默认颜色是灰色,非常毁眼.可以通过下面的设置更改为自己喜欢 ...
- Python 的三目运算
其他语言:php 判定条件?为真时的结果:为假时的结果 $a=88 $b=99 $res = $a>$b?$a>$b 搞笑的Python:令人意想不到的语法形式 true_value if ...
- Implementing Navigation with UINavigationController
Implementing Navigation with UINavigationController Problem You would like to allow your users to mo ...
- android 入门-引用库项目
http://blog.csdn.net/arui319/article/details/6831164
- bbed的使用--查看数据文件信息 & sid信息
1.得到文件的块大小和数据块个数 在Linux和Unix上,oracle提供了一个小工具dbfsize用于查看文件块大小 (可以参看[ID:360032.1]How to detect and fix ...