Description

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

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

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

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

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

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

a

aa

ab

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

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

Input

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

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

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

Output

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

Sample Input

aPaPBbP

3

1 2

1 3

2 3

Sample Output

2

1

0

HINT

1<=N<=10^5

1<=M<=10^5
输入总长<=10^5

【分析】

  •   这道题是用AC自动机里的fail指针连成的树做的。
  •   用到fail树。
  •   首先有一个朴素算法就是找到第y个单词在trie树上的路径然后沿着每一个点的fail指针走,如果找到x就加1(想想fail指针建立的过程)。
  •   由此可以运用逆向思维,以x为根的子树沿着fail指针倒着走能找到多少个y路径上的点就说明x在y上出现过几次。每次都dfs找一遍,用树状数组维护,这样可以得到70分。
  •   同时这是一个离线算法,一遍dfs,遇到一个结束标记,就做一下这个串的询问,插一个点在树状数组+1,离开这个点时-1。
  •   对于树上每个点只插入一次,时间复杂度就得到了保证。

有一个很详细的题解:http://blog.csdn.net/huzecong/article/details/7769988

代码如下:(丑)

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 100100
#define Maxl 100010 char s[Maxl];
int p[Maxn]; struct hp
{
int x,y,next,id,ans;
}qy[Maxn];int al; struct node
{
int son[],cnt,fail;
int num,rt,fa,st;
}t[Maxn];int tot; int first[Maxn],c[Maxn]; bool cmp(hp x,hp y) {return p[x.y]<p[y.y];}
bool cmp2(hp x,hp y) {return x.id<y.id;} void ins(int x,int y)
{
qy[++al].x=x;qy[al].y=y;
qy[al].next=first[x];first[x]=al;
} void upd(int x,int f)
{
t[x].cnt=;t[x].fa=f;t[x].st=;
memset(t[x].son,,sizeof(t[x].son));
} void read_trie()
{
scanf("%s",s+);
int len=strlen(s+);
memset(p,,sizeof(p));
int now=;int ql=;tot=;
for(int j=;j<=len;j++)
{
if(s[j]>='a'&&s[j]<='z')
{
int ind=s[j]-'a'+;
if(!t[now].son[ind])
t[now].son[ind]=++tot,upd(tot,now);
now=t[now].son[ind];
if(j==len) t[now].cnt++;
}
else if(s[j]=='B') now=t[now].fa;
else p[++ql]=now;
}
} queue<int > q;
void build_AC()
{
int i,j,x,y;
while(!q.empty()) q.pop();
q.push();
while(!q.empty())
{
x=q.front();
y=t[x].fail;
for(j=;j<=;j++)
{
if(t[x].son[j])
{
q.push(t[x].son[j]);
t[t[x].son[j]].fail=x?t[y].son[j]:x;
ins(t[t[x].son[j]].fail,t[x].son[j]);
}
else t[x].son[j]=t[y].son[j];
}
q.pop();
}
} void dfs(int x)
{
t[x].num=++al;t[x].rt=t[x].num;
for(int i=first[x];i;i=qy[i].next)
dfs(qy[i].y),t[x].rt=t[qy[i].y].rt;
} void add(int x,int y)
{
for(int i=x;i<=tot+;i+=i&(-i))
c[i]+=y;
} int getsum(int x)
{
int ans=;
for(int i=x;i>=;i-=i&(-i))
ans+=c[i];
return ans;
} void dfs2(int x)
{
add(t[x].num,);
if(t[x].st!=)
{
for(int i=t[x].st;;i++)
{
if(p[qy[i].y]!=x) break;
qy[i].ans=getsum(t[p[qy[i].x]].rt)-getsum(t[p[qy[i].x]].num-);
}
}
for(int i=;i<=;i++) if(t[x].son[i]&&t[t[x].son[i]].fa==x)
{
dfs2(t[x].son[i]);
}
add(t[x].num,-);
} void init()
{
memset(first,,sizeof(first));
al=;
read_trie();
build_AC();al=;
dfs();
int m;
scanf("%d",&m);
for(int i=;i<=m;i++) {scanf("%d%d",&qy[i].x,&qy[i].y);qy[i].id=i;}
sort(qy+,qy++m,cmp);
qy[].y=;
for(int i=;i<=m;i++)
if(p[qy[i].y]!=p[qy[i-].y]) t[p[qy[i].y]].st=i;
else t[p[qy[i].y]].st=t[p[qy[i-].y]].st;
memset(c,,sizeof(c));
dfs2();
sort(qy+,qy++m,cmp2);
for(int i=;i<=m;i++) printf("%d\n",qy[i].ans);
} int main()
{
init();
return ;
}

[BZOJ2434]

2016-06-16 16:55:20

【BZOJ2434-[Noi2011]】阿狸的打字机(AC自动机(fail树)+离线+树状数组)的更多相关文章

  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】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

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

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

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

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

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

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

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

  6. [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...

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

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

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

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

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

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

  10. [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组

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

随机推荐

  1. DS_Store

    .DS_Store (英文全称 Desktop Services Store)[1] 是一种由苹果公司的Mac OS X操作系统所创造的隐藏文件,目的在于存贮文件夹的自定义属性,例如文件们的图标位置或 ...

  2. PureMVC(JS版)源码解析(二):Notification类

    上篇博客,我们已经就PureMVC的设计模式进行的分析,这篇博文主要分析Notification(消息)类的实现. 通过Notification的构造函数可以看出,PureMVC中的Notificat ...

  3. android之tween动画详解

    android中一共提供了两种动画,其一便是tween动画,tween动画通过对view的内容进行一系列的图像变换(包括平移,缩放,旋转,改变透明度)来实现动画效果,动画效果的定义可以使用xml,也可 ...

  4. Android开发之隐藏Activity(活动)的标题

    隐藏一个活动的标题(如您打算向用户显示状态更新时),可以使用requestWindowFeature()方法,传递Window.FEATURE_NO_TITLE常量来控制.实现如下: protecte ...

  5. mac 神奇时光机

    http://bbs.zol.com.cn/nbbbs/d544_8216.html

  6. 【转】Angular Input格式化

    今天在Angular中文群有位同学问到:如何实现对input box的格式化.如下的方式对吗? <input type="text" ng-model="demo. ...

  7. width:100% 和 max-width:100%; 有区别吗【转藏】

    这个博客是基于“Pelican+Markdown+定制的my-gum主题”的.定制的主题将博文正文页面的 右边栏去掉,这导致在Firefox等浏览器中,正文中大的图片会突破正文块的宽度,高度也得不到限 ...

  8. 消息中间件MQ基础理论知识

    欢迎转载,转载请注明出处:http://www.cnblogs.com/lidabnu/p/5723280.html 消息中间件已经流行很长时间,一般情况下,不需要自己来从头研发.设计消息中间件,所以 ...

  9. Javascript 汉字转拼音

    调用方式: var pinyin = convert("欢迎光临"); alert(pinyin); 新建JS文件:PYConvert.js,内容如下: var PinYin = ...

  10. sql - 选出指定范围的行

    Select no=Identity(int,1,1),* Into #temptable From dbo.tName order by fName --利用Identity函数生成记录序号 Sel ...