●赘述题目

(题意就不赘述了)

●解法:

●我先想的一个比较暴力的方法(要TLE):

(ac自动机)先求出last数组(参见刘汝佳的解释:last[j]:表示j节点沿着失配指针往回走时,遇到的下一个单词节点(即单词在此结束)的编号),然后对输入的编号为y的字符串的每一个位置进行递归寻找是否能连上x字符串的结束节点。(给出失败代码片段图,就不解释了)

●正解:

(ac自动机)求出fail数组,然后以fail数组建树,如图

(看啊,红色的边和各点形成了另一棵树)

那么(看红树),若一个点在某个字符串结束节点的子树内,那么该字符串则出现在那个点所在的字符串里;如图中的a-b-c字符串和c字符串。

现在,我们若要求x字符串在y内出现了几次,就只需求以x的结束节点为根的子树内,有多少个节点是y字符串上的。

如何做呢?

将询问离线,y相同询问的弄在一起;

然后求出红树的dfs序(有点诡异,看代码);

我们再遍历一遍输入的字符串:

对于输入的‘a’-‘z’,把对应的dfs序中其出现的位置的值加1,用树状数组维护;

对于输入的‘B’,现在的字符所对应的dfs序中的位置的值减1;

对于遇到的c个‘P’,我们不难发现,现在的树状树状维护的便是第c个字符串的每一个字符在dfs序中的位置的值所加1后的结果。接着便可用区间查询求出y==c的询问的答案。

那么上代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;
struct node{
int x,y;
} q[100005];
struct edge{
int to,next;
}e[200005];
int ch[100005][27];
int val[100005],fail[100005],fa[100005],fini[100005],l[100005],r[100005],ans[100005];
int head[100005],headq[100005],nxt[100005],lat[100005],c[150000];
char x[100005];
int cnt,pnt,ent=1,dnt,lx;
int idx(char x) {return x-'a';}
void modify(int u,int d) {for(int i=u;i<=dnt;i+=i&(-i)) c[i]+=d;}
int query(int u) {int sum=0;for(int i=u;i;i-=i&(-i)) sum+=c[i]; return sum;}
void add(int u,int v)
{
e[ent]=(edge){v,head[u]};head[u]=ent++;
e[ent]=(edge){u,head[v]};head[v]=ent++;
}
void read_trie()
{
int u=0;
for(int i=1;i<=lx;i++)
{
if(x[i]=='B') u=fa[u];
else if(x[i]=='P') val[u]=++pnt,fini[pnt]=u;
else
{
int c=idx(x[i]);
if(!ch[u][c]) ch[u][c]=++cnt,fa[ch[u][c]]=u;
u=ch[u][c];
}
}
}
void get_fail()
{
queue<int> q;
for(int c=0;c<26;c++) {int u=ch[0][c]; if(u) q.push(u);}
while(!q.empty())
{
int r=q.front(); q.pop();
for(int c=0;c<26;c++)
{
if(!ch[r][c]) continue;
int u=ch[r][c];
q.push(u);
int v=fail[r];
while(v&&!ch[v][c]) v=fail[v];
fail[u]=ch[v][c];
}
}
}
//----------------------------------------------------------------------
void dfs_xu(int u,int fa)
{
l[u]=++dnt;
for(int i=head[u];i;i=e[i].next) if(e[i].to!=fa) dfs_xu(e[i].to,u);
r[u]=dnt;
}
void work()
{
int m; scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].x,&q[i].y);
nxt[i]=lat[q[i].y];
lat[q[i].y]=i;
}
for(int i=1;i<=cnt;i++) add(i,fail[i]);
dfs_xu(0,0);
int p=0,id=0;
for(int i=1;i<=lx;i++)
{
if (x[i]=='P')
{
id++;
for (int j=lat[id];j;j=nxt[j])
{
int u=fini[q[j].x];
ans[j]=query(r[u])-query(l[u]-1);
}
}
else if (x[i]=='B') modify(l[p],-1),p=fa[p];
else p=ch[p][idx(x[i])],modify(l[p],1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
int main()
{
scanf("%s",x+1);
lx=strlen(x+1);
read_trie();
get_fail();
work();
return 0;
}

●BZOJ 2434: [Noi2011]阿狸的打字机的更多相关文章

  1. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

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

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

  3. bzoj 2434 [Noi2011]阿狸的打字机 AC自动机

    [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4001  Solved: 2198[Submit][Status][D ...

  4. 【刷题】BZOJ 2434 [Noi2011]阿狸的打字机

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

  5. BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树

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

  6. bzoj 2434 [Noi2011]阿狸的打字机(fail树+离线处理+BIT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2434 [题意] 按照一定规则生成n个字符串,回答若干个询问:(x,y),问第x个字符串 ...

  7. BZOJ 2434 [Noi2011]阿狸的打字机(AC自动机)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2434 [题目大意] 给出一个打印的过程,'a'-'z'表示输入字母,P表示打印该字符串 ...

  8. bzoj 2434 [Noi2011]阿狸的打字机——AC自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2434 dfs AC自动机,走过的点权值+1,回溯的时候权值-1:走到询问的 y 串的节点,看 ...

  9. bzoj 2434: [Noi2011]阿狸的打字机

    #include<cstdio> #include<iostream> #include<cstring> #define M 100008 using names ...

随机推荐

  1. 《团队-OldNote-项目总结》

    我们小组做的是手机便签的app---OldNote 最开始我们想解决普通手机便签无法进行语音和照片的备忘这一问题,但是由于没有做过拍照和录音的经验怕由于技术原因无法达成目的,就没敢写在需求分析中.当完 ...

  2. iOS开发-OC分支结构

     BOOL类型 返回值:真:YES  假:NO BOOL数据类型占一个字节的内存空间,占位符为%d. 计算机在识别时,YES就替换成1,NO就替换成0. bool是C语言中的布尔类型,返回值为true ...

  3. JVM启动参数

    JVM参数的含义 实例见实例分析 参数名称 含义 默认值   -Xms 初始堆大小 物理内存的1/64(<1GB) 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,J ...

  4. EVA 4400存储硬盘故障数据恢复方案和数据恢复过程

    EVA系列存储是一款以虚拟化存储为实现目的的HP中高端存储设备,平时数据会不断的迁移,加上任务通常较为繁重,所以磁盘的负载相对是较重的,也是很容易出现故障的.EVA是依靠大量磁盘的冗余空间,以及故障后 ...

  5. 用java写一个servlet,可以将放在tomcat项目根目录下的文件进行下载

    用java写一个servlet,可以将放在tomcat项目根目录下的文件进行下载,将一个完整的项目进行展示,主要有以下几个部分: 1.servlet部分   Export 2.工具类:TxtFileU ...

  6. 《javascript设计模式与开发实践》阅读笔记(13)—— 职责链模式

    职责链模式 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 书里的订单的例子 假设我们负责一个售卖手机 ...

  7. JAVA_SE基础——5.第一个Java程序HelloWorld&注释的应用

    配置完JDK&环境变量后,我们就可以开始写程序了,那么程序怎么写呢,用什么工具呢,我建议 为了方便学习,我们最好在一个磁盘下建立一个专门的文件来写java程序,比如就在D盘下建立一个名为&qu ...

  8. Linux的打印rpm包的详细信息的shell脚本

    #!/bin/bash # list a content summary of a number of RPM packages # USAGE: showrpm rpmfile1 rpmfile2 ...

  9. GIT入门笔记(17)- 创建分支dev_lsq, 提交到代码

    git服务器上默认的已经有主干和test分支. 开发人员提交代码流程如下: 1.用switch to->new branch创建dev1分支 2.push branch提交到dev1分支 3.在 ...

  10. word2vec初探(用python简单实现)

    为什么要用这个? 因为看论文和博客的时候很常见,不论是干嘛的,既然这么火,不妨试试. 如何安装 从网上爬数据下来 对数据进行过滤.分词 用word2vec进行近义词查找等操作 完整的工程传到了我的gi ...