[NOI2011]阿狸的打字机

题目链接:https://www.luogu.org/problemnew/show/P2414

题目背景

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。

题目描述

打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。经阿狸研究发现,这个打字机是这样工作的:

·输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。

·按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。

·按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

a aa ab 我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

输入输出格式

输入格式:

输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

第二行包含一个整数m,表示询问个数。

接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

输出格式:

输出m行,其中第i行包含一个整数,表示第i个询问的答案。

输入输出样例

输入样例#1:

aPaPBbP
3
1 2
1 3
2 3
输出样例#1:

2
1
0

说明

数据范围:

对于100%的数据,n<=100000,m<=100000,第一行总长度<=100000。

题解:

第一次做这种比较综合的题吧。。。

这个题还是要巧妙结合AC自动机中fail树的性质的,我们知道在fail树中,如果一个父亲结点指向一个儿子结点,那么以这个父亲结点为结尾的串包含在以儿子结点结尾的串中。这个题要求包含了多少次,其实就可以联想到构造一个fail树出来了。对于每个询问x,y,那么我们只需要统计在fail树中,以x为根节点的那颗子树上面包含了多少在1~y这条链上的结点就是了。

具体做法为离线做法,就是先对所有的询问x,y,连y->x的一条边。之后我们在fail树中跑一次dfs序,毕竟我们需要子树的信息嘛。

然后就从0开始,一个一个字符串加进去,如果出现小写字母,那么就让这个点的值加上1;如果出现“P”,就进行相应的回答;否则出现B,就让对应的值减去1。这里的操作可以在

回答询问的时候统计子树权值和就行了,这个过程可以用树状数组来实现。这些操作都可以在前缀树上面完成(实际上是一条链)。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+;
char s[N];
int pos[N],head[N],fa[N],in[N],out[N],ans[N];
int tot,num;
queue <int> q;
struct Edge{
int v,next,id;
}e[N<<];
void adde(int u,int v,int id){
e[tot].v=v;e[tot].next=head[u];e[tot].id=id;head[u]=tot++;
}
struct Aho_Corasick{
int Size;
int ch[N][];
int val[N];
int fail[N];
void init(){
Size=-;
newnode();
}
int newnode(){
memset(ch[++Size],,sizeof(ch[]));
fail[Size]=;
return Size;
}
void insert(char *s){
int l=strlen(s);
int u=;
for(int i=;i<l;i++){
if(s[i]=='P'){
pos[++num]=u;
}else if(s[i]=='B'){
u=fa[u];
}else{
int idx=s[i]-'a';
if(!ch[u][idx]) ch[u][idx]=newnode();
fa[ch[u][idx]]=u;u=ch[u][idx];
}
}
}
void Getfail(){
while(!q.empty()) q.pop();
for(int i=;i<;i++){
if(ch[][i]) q.push(ch[][i]),adde(,ch[][i],);
}
while(!q.empty()){
int cur=q.front();q.pop();
for(int i=;i<;i++){
if(ch[cur][i]){
fail[ch[cur][i]]=ch[fail[cur]][i];
q.push(ch[cur][i]);
adde(ch[fail[cur]][i],ch[cur][i],);
}else{
ch[cur][i]=ch[fail[cur]][i];
}
}
}
}
}ac;
int dfn;
void dfs(int u,int pa){
in[u]=++dfn;
for(int i=head[u];i!=-;i=e[i].next){
int v=e[i].v;
if(v!=pa) dfs(v,u);
}
out[u]=dfn;
}
int c[N];
int lowbit(int x){
return x&(-x);
}
void add(int pos,int val){
for(int i=pos;i<=N-;i+=lowbit(i)) c[i]+=val;
}
int query(int l){
int ans=;
for(int i=l;i>;i-=lowbit(i)) ans+=c[i];
return ans ;
}
int main(){
scanf("%s",s);
memset(head,-,sizeof(head));tot=;
ac.init();
ac.insert(s);
ac.Getfail();
dfs(,-);
memset(head,-,sizeof(head));tot=;
int q;cin>>q;
for(int i=,x,y;i<=q;i++){
scanf("%d%d",&x,&y);
adde(y,x,i);
}
int l=strlen(s);
int cnt=,u=;;
for(int i=;i<l;i++){
if(s[i]=='B'){
add(in[u],-);u=fa[u];
}else if(s[i]=='P'){
cnt++;
int now=pos[cnt];
for(int j=head[cnt];j!=-;j=e[j].next){
int x=pos[e[j].v];
ans[e[j].id]=query(out[x])-query(in[x]-);
}
}else{
int idx=s[i]-'a';
u=ac.ch[u][idx];
add(in[u],);
}
}
for(int i=;i<=q;i++) printf("%d\n",ans[i]);
return ;
}

BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)的更多相关文章

  1. BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组

    题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...

  2. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  3. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  4. NOI 2011 阿狸的打字机 (AC自动机+dfs序+树状数组)

    题目大意:略(太长了不好描述) 良心LOJ传送门 先对所有被打印的字符串建一颗Trie树 观察数据范围,并不能每次打印都从头到尾暴力建树,而是每遍历到一个字符就在Trie上插入这个字符,然后记录每次打 ...

  5. BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)

    题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...

  6. BZOJ_2434_[NOI2011]_阿狸的打字机_(AC自动机+dfs序+树状数组)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2434 给出\(n\)个字符串,\(m\)个询问,对于第\(i\)个询问,求第\(x_i\)个字 ...

  7. CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)

    The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...

  8. BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组

    BZOJ_3881_[Coci2015]Divljak_AC自动机+dfs序+树状数组 Description Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是 ...

  9. BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)

    Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4140  Solved: 2276[Submit][Status][Discuss] Descript ...

随机推荐

  1. HDU - 6441(费马大定理)

    链接:HDU - 6441 题意:已知 n,a,求 b,c 使 a^n + b^n = c^n 成立. 题解:费马大定理 1.a^n + b^n = c^n,当 n > 2 时无解: 2. 当 ...

  2. Ubuntu—查看进程并关闭进程

    环境:Ubuntu终端 命令:ps -aux 功能:查看进程信息 命令:kill 进程号(PID) 功能:杀死进程

  3. eos智能合约开发最佳实践

    安全问题 1.可能的错误 智能合约终止 限制转账限额 限制速率 有效途径来进行bug修复和提升 2.谨慎发布智能合约 对智能合约进行彻底的测试 并在任何新的攻击手法被发现后及时制止 赏金计划和审计合约 ...

  4. sql月,年,统计报表sql报表

    select DevName as 设备名称, count(flux) as 流量数据个数, max(flux) as 流量最大值, min(flux) as 流量最小值, avg(flux) as ...

  5. apache访问403错误

    1.排查selinux 2.目录权限 3.WEB主目录是否正确

  6. 第八章 IO库

    8.1&&8.2 #include <iostream> #include <vector> #include <string> using nam ...

  7. Check the string

    A has a string consisting of some number of lowercase English letters 'a'. He gives it to his friend ...

  8. Daily Scrum 11

    今天我们小组开会内容分为以下部分: part 1: 针对学长的搜索算法进行优化,每人发表自己的看法; part 2:对积分系统.防滥用.搜索算法优化部分代码任务的讨论和分工: part 3:进行明日的 ...

  9. Serialable与Parcelable

    Serializable和Parcelable比较        Serializable的作用是为了保存对象的属性到本地文件.数据库.网络流.rmi以方便数据传输,当然这种传输可以是程序内的也可以是 ...

  10. Java之I/O流(第2部分)

    1. 节点类类型: 2. 访问文件: Demo_1: import java.io.FileInputStream; import java.io.FileNotFoundException; imp ...