【题解】[NOI2011]阿狸的打字机
\(\text{Solution:}\)
首先观察三种操作:一种是插入一个字符,一种是退回上一步(回到父亲节点)。
所以,我们可以对操作串进行模拟,并处理出每一个串在树上的位置。
接下来,我们考虑如何处理询问。\(y\)是需要跑的串,于是我们应按照\(y\)排序以保证在处理这个\(y\)之前,它本身或者其他的东西没有加进树上过。
考虑同样的模板处理方法:对于一个串出现了几次,我只需要统计这个串结尾编号在\(fail\)树子树中的\(cnt\)个数。
于是自然想到维护子树和的有利武器:\(dfs\)序和树状数组。
于是,我们可以预先处理掉\(dfs\)序,并直接模拟在\(opt\)串上进行的移动操作即可。
这里解释模板的处理思路:首先,既然我们跳到了这个\(fail\)指针,说明我们一定匹配完过当前这整个\(fail\)指针(参考定义)。
观察\(fail\)树上的结构,我们结合上面所述可以知道,所有直接或间接指向\(x\)这个节点的\(fail\)指针,只要跳到了,就一定匹配到过整个串\(x\).
于是,我们可以统计\(fail\)树上\(x\)子树中的\(cnt\),注意每匹配到一个点,应该在\(fail\)树上把从它到根节点的路径上全部加\(1.\)但实际上我们只需要在匹配到的时候对它单点\(+1,\)再\(dfs\)一下\(fail\)树就可以了。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2000100;
int tot,tr[MAXN],fa[MAXN];
int pos[MAXN],num;
struct Tree{
int ch[26],fail;
}T[MAXN];
vector<int>to[MAXN];
struct Qu{
int x,y,id;
}Q[MAXN];
inline bool cmp(Qu a,Qu b){return a.y<b.y;}
char opt[MAXN];
void Build(char *s,int L){
int u=0;
for(int i=0;i<L;++i){
if(opt[i]=='B')u=fa[u];
else if(opt[i]=='P')pos[++num]=u;
else if(T[u].ch[s[i]-'a'])u=T[u].ch[s[i]-'a'];
else T[u].ch[s[i]-'a']=++tot,fa[tot]=u,u=tot;//介于本题需要有跳回上一步的操作,所以需要记录一下fa
}
//对操作串进行处理,并记录下每一个询问串在树上的位置
}
void bfs(){
queue<int>q;
for(int i=0;i<26;++i){
if(T[0].ch[i]){
int v=T[0].ch[i];
T[v].fail=0;
q.push(v);
}
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;++i){
if(T[u].ch[i]){
int v=T[u].ch[i];
T[v].fail=T[T[u].fail].ch[i];
q.push(v);
}
else T[u].ch[i]=T[T[u].fail].ch[i];
}
to[T[u].fail].push_back(u);
}
//建立AC自动机并建立fail树
}
int dfn[MAXN],I,ed[MAXN];
void dfs(int u){
dfn[u]=++I;
for(int i=0;i<to[u].size();++i)dfs(to[u][i]);
ed[u]=I;
//处理出每一个树上节点的dfs序列,注意是树上的
}
inline int lowbit(int x){return (x&(-x));}
inline void add(int x,int v){for(;x<=I;x+=lowbit(x))tr[x]+=v;}
inline int query(int x){int res=0;for(;x;x-=lowbit(x))res+=tr[x];return res;}
//树状数组不解释
int ans[MAXN],m;
int main(){
scanf("%s",opt);
int len=strlen(opt);
Build(opt,len);
bfs();dfs(0);
//预处理
scanf("%d",&m);
for(int i=1;i<=m;++i)scanf("%d%d",&Q[i].x,&Q[i].y),Q[i].id=i;
sort(Q+1,Q+m+1,cmp);//按照询问的y从小到大处理
int u=0,r=0,l=0;
for(int i=1;i<=m;++i){
while(r<Q[i].y){
if(opt[l]=='P')r++;//更新目前处理到第几个串
else if(opt[l]=='B'){
add(dfn[u],-1);
u=fa[u];
}//删掉当前u所在字符
else{
u=T[u].ch[opt[l]-'a'];
add(dfn[u],1);
}//更新下一个字符
l++;//操作串后移
}
ans[Q[i].id]=query(ed[pos[Q[i].x]])-query(dfn[pos[Q[i].x]]-1);//注意双映射!
}
for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}
【题解】[NOI2011]阿狸的打字机的更多相关文章
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- [NOI2011]阿狸的打字机(好题!!!!)
2785: [NOI2011]阿狸的打字机 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 7 Solved: 3[Submit][Status][We ...
- P2414 [NOI2011]阿狸的打字机
P2414 [NOI2011]阿狸的打字机 AC自动机+树状数组 优质题解 <------题目分析 先AC自动机搞出Trie图 然后根据fail指针建一只新树 把树映射(拍扁)到一个序列上,用树 ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
- BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)
[NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
- [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组
[NOI2011] 阿狸的打字机 题目描述: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 3610 Solved: 1960 [Submit][S ...
- bzoj 2434 [Noi2011]阿狸的打字机 AC自动机
[Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4001 Solved: 2198[Submit][Status][D ...
- 洛谷 P2414 [NOI2011]阿狸的打字机 解题报告
P2414 [NOI2011]阿狸的打字机 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母 ...
随机推荐
- 【Android】时间选择器,选择日期DatePicker 简单详解demo及教程
作者:程序员小冰,GitHub主页:https://github.com/QQ986945193 新浪微博:http://weibo.com/mcxiaobing 首先给大家看一下我们今天这个最终实现 ...
- 攻防世界——web新手练习区解题记录<1>(1-4题)
web新手练习区一至四题 第一题view_source: 题目说右键不管用了,我们先获取在线场景来看一看,我们看到这样一个网页,并且右键确实点了没什么反应,而用到右键一般就是查看网页源码 用快捷键(F ...
- 递推dp数位
1-n里有多少个1 #include <cstdio> #include <iostream> using namespace std; int main() { int n= ...
- JVM内存区域以及各区域的内存溢出异常,内存分代策略,垃圾收集算法,各种垃圾收集器
本文整理自周志明老师的<深入理解Java虚拟机-JVM高级特性与最佳实践>第3版的第二章和第三章. 加上了一些网上拼拼凑凑的图片,个人认为很多博客复制来复制去,最后的东西都看不懂,所以从书 ...
- [BUUOJ记录] [SUCTF 2019]CheckIn
比较经典的一道文件上传题,考察.user.ini控制解析图片方式 打开题目给出了上传功能,源代码里也没有任何提示,看来需要先测试一下过滤 前后依次提交了php,php5,php7,phtml拓展名的文 ...
- 阿里面试:dubbo的服务引用过程
点赞再看,养成习惯,微信搜一搜[三太子敖丙]关注这个喜欢写情怀的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系 ...
- 【CF】Sereja and Arcs
#include <bits/stdc++.h> #define llong long long using namespace std; const int N = 1e5; const ...
- docker 停止、启动、删除镜像指令
容器 docker ps // 查看所有正在运行容器 docker stop containerId // containerId 是容器的ID docker ps -a // 查看所有容器 dock ...
- 关于Vue-CLI的那些事儿
Vue CLI是基于Vue.js进行快速发展的完整系统,提供了: 交互式的项目脚手架 实现零配件的原型开发 图形化的创建和管理项目的界面 基本框架的构建: . ├── build/ # webpack ...
- 单元测试unittest(基于数据驱动的框架:unittest+HTMLTestRunner/BeautifulReport+yaml+ddt)
一.定义 unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果 ...