【题解】[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'两个字母 ...
随机推荐
- 【Linux利用远程SSH连接】SecureCRT中文出现乱码解决办法 Linux服务器技术
1. 修改远程linux机器的配置 vim /etc/sysconfig/i18n 把LANG改成支持UTF-8的字符集 如: LANG="zh_CN.UTF-8″ 或者 ...
- Python基本
Python基本规则 1.面向对象的跨平台的编程语言 2.文件类型是.py, 3.一个文件是一个模块module,运行整个文件 4.不支持非英文字符,区分大小写 5.一行是一条语句,多条语句写一行用; ...
- Almost All Divisors(求因子个数及思维)
---恢复内容开始--- We guessed some integer number xx. You are given a list of almost all its divisors. Alm ...
- 深入了解Netty【八】TCP拆包、粘包和解决方案
1.TCP协议传输过程 TCP协议是面向流的协议,是流式的,没有业务上的分段,只会根据当前套接字缓冲区的情况进行拆包或者粘包: 发送端的字节流都会先传入缓冲区,再通过网络传入到接收端的缓冲区中,最终由 ...
- hdu6704 2019CCPC网络选拔赛1003 K-th occurrence 后缀自动机+线段树合并
解题思路: fail树上用权值线段树合并求right/endpos集合,再用倍增找到待查询串对应节点,然后权值线段树求第k大. #include<bits/stdc++.h> using ...
- Linux—账号管理及命令使用详解
关注微信公众号:CodingTechWork,一起学习进步. 引言 在Linux系统中,我们常常会看到目录或文件的所属关系: [root@linux01 ~]# ll -d test.sh -rw ...
- 13_Python的面向对象编程-类class,对象object,实例instance
1.面向对象概述 1.类是用来描述对象的工具,把拥有相同属性和行为的对象分为一组 2.对象是由类实例化出来的一个具体的对象 属性: 对象拥有的名词,用变量表示 ...
- JsonAnalyzer 源码下载
下载地址:https://files.cnblogs.com/files/heyang78/JsonAnalyzer20200518-01.zip 测试用例:https://www.cnblogs.c ...
- 与C中printf并列的System.out.printf 用法(转载)
转载地址: https://blog.csdn.net/qq_39017218/article/details/80042287 printf的格式控制的完整格式: % - 0 m.n l或h ...
- 20190916-01linux文件与目录结构 000 001
1./bin 是Binary的缩写,这个目录存放着最经常使用的命令 2./sbin s就是Super User的意思,这里存放的是系统管理员使用的系统管理程序 3./home 存放普通用户的主目录,在 ...