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

[NOI2011] 阿狸的打字机

题目描述:

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

打字机上只有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个询问的答案。

 

数据范围:

\(n,m<= 10^{5}\) 

 

首先,如果模拟按键的过程(暂时无视询问),把所有操作后的串都提取出来

可以形成一棵Trie树

 

题目中又正好提到了匹配,那么不妨继续建出AC自动机

如果对AC自动机有了解,那么不难知道一个点及其fail后继有多少点被标记,那么它代表的串出现的次数就是被标记的点数

因此,如果把AC自动机的fail树拿出来,原问题可以转化为:

 

维护一棵树,支持:

给定一堆被标记的点,查询一个点的子树内被标记的点的个数

 

这是不可做的

但是,原问题有特殊性

这些被标记的点是1个1个标记的,因此,我们可以离线根据x排序

 

那么,现在我们可以再模拟一遍,当模拟到x次操作时,就可以回答跟x有关的回答了。

注意到原问题转化后相当于要支持:单点修改,子树查询

拿树状数组维护dfs序就能解决这个问题。

复杂度O(\(m \log n\))

 

代码在此

 

posted @ 2018-04-18 13:05  remoon  阅读(141)  评论(0编辑  收藏  举报