http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23083

Description

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

经阿狸研究发现,这个打字机是这样工作的:

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

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

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

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

a

aa

ab

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

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

Sample Input

aPaPBbP
3
1 2
1 3
2 3

Sample Output

2
1
0

题解:这道题做了好久。。哭泣。。。。。。。

主要是超时的问题。

fail树:按照AC自动机上fail的反向边建立的树。

如样例:

可以知道:failtree上,任意一点所代表的子串(即以trie上根到该点的串)是它在fail树上的子树任意一点的子串。

就是说,x是y的祖先,那么以y为结尾的串一直fail可以fail到x,就是x是y的子串。

那么现在可以得出一个简单粗暴的方法:

对于每个询问(x,y),求x在y上出现的次数,我们就可以在fail树上找到x串末尾的点A,然后询问y串在fail树上的每一个点是否是x的子树中的点,是就ans++。

但是明显,这个方法慢出天际了。。。。

优化:

(三颗星)离线。在fail树上用dfn给节点编号,则每一个点的子树在节点号上是连续的一段。在trie上走一遍,每到一个点x就在树状数组的dfn[x]位置+1,每离开一个点就在树状数组的dfn[x]位置-1。然后每当走到一个串的末尾,就询问每个对应要询问的x串,给fail树上它的子树求和,就是树状数组上getsum A~next[A]-1,这样就求出了y上多少个点为末尾可以fail到x,就是该询问(x,y)的答案。

后面就是我的错误点了:

(1)循环字符串的时候不要打for(int i=0;i<strlen(s);i++) ... 拿个变量存一下strlen(s)。。。超慢的。。

(2)做trietree的时候不用每次从头开始。。接着上一次的末尾就可以了。。快超多。。

(3)最后询问的时候不要把所有询问扫一遍。。用个first存y的边目录啊。。

血与泪啊。。

代码如下:

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
using namespace std; const int N=,S=;
struct node{
int k,fa,fail,son[];
}a[N];
struct edge{
int x,y,next,fa,ans;
}b[N],t[N];
char s[N];
int pre,m,tl,sl,num,cnt_s,len,cnt_dfn;
int last[N],c[N],sk[N],dfn[N],next[N],first[N],fir[N];
queue<int> q; void clear(int x)
{
a[x].fa=a[x].k=a[x].fail=;
memset(a[x].son,,sizeof(a[x].son));
} void buildAC()
{
while(!q.empty()) q.pop();
for(int i=;i<=S;i++)
if(a[].son[i]) q.push(a[].son[i]);
while(!q.empty())
{
int x=q.front();q.pop();
int fail=a[x].fail;
for(int i=;i<=S;i++)
{
if(a[x].son[i])
{
a[a[x].son[i]].fail=a[fail].son[i];
q.push(a[x].son[i]);
}
else a[x].son[i]=a[fail].son[i];
}
}
} void ins(int x,int y,bool bk)
{
if(!bk)
{
b[++len].x=x;b[len].y=y;
b[len].next=first[x];first[x]=len;
}
else
{
t[++tl].x=x;t[tl].y=y;t[tl].ans=;
t[tl].next=fir[x];fir[x]=tl;
}
} void dfs(int x)
{
dfn[x]=++cnt_dfn;
for(int i=first[x];i;i=b[i].next)
{
int y=b[i].y;
dfs(y);
}
next[x]=cnt_dfn;
} void build_fail_tree()
{
for(int i=;i<=num;i++) ins(a[i].fail,i,);
dfs();
} int lowbit(int x){return x&(-x);}
void add(int x,int d){for(int i=x;i<=N-;i+=lowbit(i)) c[i]+=d;}
int getsum(int x)
{
int ans=;
for(int i=x;i>=;i-=lowbit(i)) ans+=c[i];
return ans;
} int main()
{
freopen("a.in","r",stdin);
freopen("me.out","w",stdout);
num=;cnt_s=;cnt_dfn=;len=;pre=;tl=;clear();
memset(fir,,sizeof(fir));
memset(first,,sizeof(first));
memset(c,,sizeof(c));
scanf("%s",s);
//build trie tree
int strl=strlen(s),now=;
for(int i=;i<strl;i++)
{
if(s[i]=='P')
{
a[now].k=;
last[++cnt_s]=now;
}
else if(s[i]=='B') now=a[now].fa;
else
{
int ind=s[i]-'a'+;
if(!a[now].son[ind])
{
num++;clear(num);
a[now].son[ind]=num;
a[num].fa=now;
}
now=a[now].son[ind];
}
}
//build ac
buildAC();
//build fail tree
build_fail_tree();
scanf("%d",&m);
for(int i=;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(y,x,);
}
//find
now=,cnt_s=;
for(int i=;i<strl;i++)
{
if(s[i]=='B')
{
add(dfn[now],-);
now=a[now].fa;
}
else if(s[i]=='P')
{
cnt_s++;
for(int j=fir[cnt_s];j;j=t[j].next)
{
int st=dfn[last[t[j].y]],ed=next[last[t[j].y]];
t[j].ans=getsum(ed)-getsum(st-);
}
}
else
{
int ind=s[i]-'a'+;
now=a[now].son[ind];
add(dfn[now],);
}
}
for(int i=;i<=m;i++)
printf("%d\n",t[i].ans);
return ;
}

【bzoj2434-阿狸的打字机】AC自动机+fail树+优化的更多相关文章

  1. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

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

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

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

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

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

  4. [NOI2011][bzoj2434] 阿狸的打字机 [AC自动机+dfs序+fail树+树状数组]

    题面 传送门 正文 最暴力的 最暴力的方法:把所有询问代表的字符串跑一遍kmp然后输出 稍微优化一下:把所有询问保存起来,把模板串相同的合并,求出next然后匹配 但是这两种方法本质没有区别,都是暴力 ...

  5. BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)

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

  6. BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...

  7. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

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

  8. BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 3610  Solved: 1960 [Submit][S ...

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

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

随机推荐

  1. Go语言类型switch

    switch还可以用于判断变量类型.使用方式为T.(type),即在变量后加上.(type).见代码: package main import ( "fmt" ) func mai ...

  2. 安装v2meet客户端 进入会议依然 提示 您还未安装视频会议的客户端,请下载安装

    解决办法 1.安装软件,要用管理员权限安装 2.装一个360浏览器,登录会议,这样就成功了.原装IE9却不行. 估计是IE9做了一些安全限制,由于时间关系就没有再处理了.

  3. 20145129 《Java程序设计》第3周学习总结

    20145129 <Java程序设计>第3周学习总结 教材学习内容总结 类与对象 定义类 一个原始码中可以有多个类定义,但只有一个是公开类(public),并且文档中的主文档名必须和公开类 ...

  4. Asp.net操作Excel(终极方法NPOI)(转)

    原文:Asp.net操作Excel(终极方法NPOI) 先去官网:http://npoi.codeplex.com/下载需要引入dll(可以选择.net2.0或者.net4.0的dll),然后在网站中 ...

  5. Kibana4学习<一>

    Kibana4 安装方式依然简单,你可以在几分钟内安装好 Kibana 然后开始探索你的 Elasticsearch 索引.只需要预备: Elasticsearch 1.4.4 或者更新的版本 一个现 ...

  6. IIS8中 出现ashx 401:未授权,uploadify上传文件失败

    环境:阿里云服务器 windows2012  + IIS8 +asp.net 访问IIS 出现能正常访问aspx页面,但是通过ajax访问ashx上传文件的时候就出现ashx  Status Code ...

  7. 《Soft Skill》一书中的好句子

    The biggest mistake that you can make is to believe that you are working for somebody else. Job secu ...

  8. Reveal 破解

    永久试用Reveal,只需要打开 ~/Library/Preferences/com.ittybittyapps.Reveal.plist 把IBAApplicationPersistenceData ...

  9. Oracle Goldengate和Oracle Data Integrator的初步认识

    免责声明:     本文中使用的部分图片来自于网络,如有侵权,请联系博主进行删除 1. Oracle Glodengate是什么? GoldenGate是oracle的一种基于数据库日志的数据同步软件 ...

  10. HDU 2196 求树上所有点能到达的最远距离

    其实我不是想做这道题的...只是今天考试考了一道类似的题...然后我挂了... 但是乱搞一下还是有80分....可惜没想到正解啊! 所以今天的考试题是: 巡访 (path.pas/c/cpp) Cha ...