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的答案
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 111111 7 8 struct Edge{ 9 int v,next; 10 }edge[MAXN]; 11 int NE,head[MAXN]; 12 void addEdge(int u,int v){ 13 edge[NE].v=v; edge[NE].next=head[u]; 14 head[u]=NE++; 15 } 16 17 int tn,ch[MAXN][26],fa[MAXN],flag[MAXN],fail[MAXN]; 18 int belong[MAXN],bn,rbelong[MAXN]; 19 char str[111111]; 20 void insert(){ 21 int x=0; 22 for(int i=0; str[i]; ++i){ 23 if(str[i]=='B'){ 24 x=fa[x]; 25 }else if(str[i]=='P'){ 26 flag[x]=1; 27 belong[x]=++bn; 28 rbelong[bn]=x; 29 }else{ 30 int y=str[i]-'a'; 31 if(ch[x][y]==0) ch[x][y]=++tn,fa[ch[x][y]]=x; 32 x=ch[x][y]; 33 } 34 } 35 } 36 void getfail(){ 37 queue<int> que; 38 for(int i=0; i<26; ++i){ 39 if(ch[0][i]){ 40 que.push(ch[0][i]); 41 addEdge(0,ch[0][i]); 42 } 43 } 44 while(!que.empty()){ 45 int x=que.front(); que.pop(); 46 for(int i=0; i<26; ++i){ 47 if(ch[x][i]){ 48 que.push(ch[x][i]); 49 fail[ch[x][i]]=ch[fail[x]][i]; 50 addEdge(fail[ch[x][i]],ch[x][i]); 51 }else ch[x][i]=ch[fail[x]][i]; 52 } 53 } 54 } 55 56 int dfn,l[MAXN],r[MAXN],par[MAXN]; 57 void dfs(int u){ 58 l[u]=++dfn; 59 for(int i=head[u]; i!=-1; i=edge[i].next){ 60 int v=edge[i].v; 61 par[v]=u; 62 dfs(v); 63 } 64 r[u]=dfn; 65 } 66 67 int tree[MAXN<<2],N,x,y; 68 void update(int i,int j,int k){ 69 if(i==j){ 70 tree[k]+=y; 71 return; 72 } 73 int mid=i+j>>1; 74 if(x<=mid) update(i,mid,k<<1); 75 else update(mid+1,j,k<<1|1); 76 tree[k]=tree[k<<1]+tree[k<<1|1]; 77 } 78 int query(int i,int j,int k){ 79 if(x<=i && j<=y){ 80 return tree[k]; 81 } 82 int mid=i+j>>1,res=0; 83 if(x<=mid) res+=query(i,mid,k<<1); 84 if(y>mid) res+=query(mid+1,j,k<<1|1); 85 return res; 86 } 87 88 struct Query{ 89 int x,y,ans,next; 90 }que[MAXN]; 91 int qhead[MAXN],qNE,order[MAXN]; 92 void addQuery(int x,int y){ 93 que[qNE].x=x; que[qNE].y=y; que[qNE].next=qhead[y]; 94 qhead[y]=qNE++; 95 } 96 97 void doit(){ 98 int now=0; 99 for(int i=0; str[i]; ++i){ 100 if(str[i]=='B'){ 101 x=l[now]; y=-1; 102 update(1,N,1); 103 now=fa[now]; 104 }else if(str[i]=='P'){ 105 for(int j=qhead[belong[now]]; j!=-1; j=que[j].next){ 106 x=l[rbelong[que[j].x]]; y=r[rbelong[que[j].x]]; 107 que[j].ans=query(1,N,1); 108 } 109 }else{ 110 now=ch[now][str[i]-'a']; 111 x=l[now]; y=1; 112 update(1,N,1); 113 } 114 } 115 } 116 int main(){ 117 scanf("%s",str); 118 insert(); 119 memset(head,-1,sizeof(head)); 120 getfail(); 121 dfs(0); 122 for(N=1; N<dfn; N<<=1); 123 memset(qhead,-1,sizeof(qhead)); 124 int m,a,b; 125 scanf("%d",&m); 126 for(int i=0; i<m; ++i){ 127 scanf("%d%d",&a,&b); 128 order[i]=qNE; 129 addQuery(a,b); 130 } 131 doit(); 132 for(int i=0; i<m; ++i){ 133 printf("%d\n",que[order[i]].ans); 134 } 135 return 0; 136 }
转载于:https://www.cnblogs.com/WABoss/p/5407253.html
BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)相关推荐
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 2545 Solved: 1419 [Submit][S ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
- BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...
- 【bzoj2434】[Noi2011]阿狸的打字机 AC自动机+Dfs序+树状数组
题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...
- P2414 NOI2011阿狸的打字机 [AC自动机,dfs序]
阿狸的打字机 题解 题目中给出的字符串就是构建TrieTrieTrie树的顺序.我们将字符串依次读入,每读入一个小写字符就相当于在TrieTrieTrie树当前节点下插入一个小写字符,读入BBB时,就 ...
- BZOJ 2434 NOI2011阿狸的打字机 AC自动机+树状数组
如果你还没学AC自动机,请看这篇博客 Problem bzoj通道 洛谷通道 Solution 简单的说来,其实就是要快速求一个字符串在另一个字符串中出现了多少次.考虑构造AC自动机. 首先可以想到很 ...
- 【bzoj2434】阿狸的打字机 AC自动机+树状数组
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 [题解] 这是一道很神的题. 先建一个AC自动机,这里需要维护一下父结点,以便删除时 ...
- [luogu2414 NOI2011]阿狸的打字机 (AC自动机)
传送门 Solution 我们知道AC自动机上如果有一点A的fail[A]->B那么B为A的一个后缀 那么我们的问题\((x,y)\)就变为在y中有多少个点直接或间接连向x的终止节点 如果写暴力 ...
- BZOJ2434 [Noi2011]阿狸的打字机
AC自动机+树状数组 先建出fail树,对于查询x在y中出现几次,就等于在x为根的子树下有多少个节点为单词y在tire树路径上所在的节点,可用dfs+树状数组离线求出答案. #include<c ...
- 【bzoj 2434】【codevs 1946】[Noi2011]阿狸的打字机(AC自动机)
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 2477 Solved: 1382 [Submit][S ...
最新文章
- canopy算法 java_mahout源码canopy算法分析之二CanopyMapper
- java 获取 jframe 内容_Java如何获取组件的JFrame?
- 设计模式:000设计模式与面向对象介绍
- html 自定义文件选择,html5 自定义文件上传
- 自动登录Windows系统
- python 按日期筛选数据并计算均值
- MKS 在线编译工具使用说明书
- DWG文件打开速度太慢怎么办!
- 2020年中国高精度卫星导航定位行业现状、竞争格局及发展前景分析,基于北斗系统全面建成,定位技术向多场景发展「图」
- 白话区块链技术-区块链工程师大讲堂
- github下载文件时让输入用户名和密码
- python取整数部分的几种方法
- 笔记 | spark安装及入门会遇到哪些坑
- 食品网站和学校网站设计区别于总结
- sl软件安装方式总结
- wp8 导出短信 到android,如何从outlook同步联系人头像以及管理短信呢
- memcpy函数实现及其优化
- 巧玩SpringCloud——使用Eureka搭建服务注册中心与服务发现
- 用小米手机的都是屌丝???
- 微信小程序开发个人笔记(2)
热门文章
- 不胜唏嘘!衰落的苹果与崛起的荣耀
- [CF617E]XOR and Favorite Number/[CQOI2018]异或序列
- H3C交换机做DHCP
- Pytorch:Tensor(张量)的使用
- setFitView的zoom只是整数,导致缩放尺寸不合适的解决方案
- 记录开发过程中第一次遇到的回调地狱
- vue学习笔记-14-过滤器
- gazebo 直接获取传感器数据_如何以最简单的方式获取传感器数据?
- 小程序如何上传代码到服务器,云服务器怎么上传小程序代码
- java opencv gamma_OpenCV函数cvAddWeighted调整alpha和gamma值 | 学步园