Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 4140  Solved: 2276
[Submit][Status][Discuss]

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

Source

Trie

非常不错的一道题目

首先暴力把每个字符串扔到trie树里并打上标记,$O(M)$

我们查询的是第$x$个字符串在第$y$个字符串中出现了多少次,如果一次一次的查肯定是太浪费了。

考虑能不能一次多查几个,如果你做过这道题的话肯定能想到是AC自动机。

这样我们对于相同的$y$,仅做一次查询就行了。为了更方便的查找,我们对$y$进行排序,这样就可以$O(1)$的维护出$y$的形态

回到上一个问题,考虑如何查询出现次数,

根据$fail$树的性质,我们不难发现,若$x$节点在$root$到$y$任意一个节点的$fail$树上,那么$x$一定就是$y$的子串

(这里简单证明一下:判断一个串是否是另一个串的子串可以转换为判断这个串是否是另一个串前缀后缀,我们枚举从根到$y$的路径,实际上就是枚举了$y$的前缀,而在$fail$树上查找,实际上就是在枚举$y$的后缀)

这样查询一次的复杂度为$O(siz)$,若所有的$y$全不相同肯定还是会凉凉

接下来就是神仙操作了!

考虑转化问题,

若$x$节点在$root$到$y$任意一个节点的$fail$树上,那么$x$一定就是$y$的子串

同理,若$y$在$x$的子树中,那么$x$一定是$y$的子串

这样我们在枚举$y$的时候,可以在经过的路径上打上$+1$的标记(退出的时候打上$-1$的标记),当遇到当前节点为$y$时,查询一下$x$的子树的和就好了

这样的复杂度仍然没有降下来为,$O(siz^2)$

但是!别忘了在树上有一种经典的操作—>dfs序+树状数组

然后这题就$O(siz \log siz)$的做完了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN = 1e5 + ;
inline int read() {
char c = getchar(); int x = , f = ;
while(c < '' || c > '') {if(c == '-') f = -; c = getchar();}
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * f;
}
const int root = , B = ;
int Num, N;
char s[MAXN];
struct Query {
int x, y, ID, ans;
bool operator < (const Query &rhs) const {
return y == rhs.y ? x < rhs.x : y < rhs.y;
}
}Q[MAXN];
vector<int> v[MAXN];
int ch[MAXN][], fa[MAXN], fail[MAXN], val[MAXN], siz[MAXN], tot = , Pos[MAXN], meiyong = ;
void Build() {
int now = root;
for(int i = ; i <= N; i++) {
int x = s[i] - 'a';
if(x == -) {now = fa[now]; continue;}
if(x == -) {Pos[++meiyong] = now; continue;}
if(!ch[now][x]) ch[now][x] = ++tot;
fa[ch[now][x]] = now; now = ch[now][x];
}
}
void GetFail() {
queue<int> q;
for(int i = ; i < B; i++) if(ch[root][i]) q.push(ch[root][i]);
while(!q.empty()) {
int p = q.front(); q.pop();
for(int i = ; i < B; i++)
if(!ch[p][i]) ch[p][i] = ch[fail[p]][i];
else fail[ch[p][i]] = ch[fail[p]][i], q.push(ch[p][i]);
v[fail[p]].push_back(p);
}
}
int ID[MAXN], cnt; //ID[i]表示第i个节点在fail树上的编号
void dfs(int x) {
ID[x] = ++cnt; siz[ID[x]] = ;
for(int i = ; i < v[x].size(); i++)
dfs(v[x][i]), siz[ID[x]] += siz[ID[v[x][i]]];
}
struct BIT {
#define lb(x) (x & (-x))
int Tree[MAXN];
int add(int pos, int val) {
for(int i = pos; i <= cnt; i += lb(i))
Tree[i] += val;
}
int sum(int pos) {
int ans = ;
for(int i = pos; i >= ; i -= lb(i))
ans += Tree[i];
return ans;
}
int QUERY(int x, int y) {
return sum(y) - sum(x - );
}
}T;
void Solve() {
int now = root, cur = , world = ;
for(int i = ; i <= N; i++) {
int x = s[i] - 'a';
if(x == -) {T.add(ID[now], -), now = fa[now]; continue;}
else if(x == -) {
world++;
for(int x; Q[cur].y == world; cur++)
x = Pos[Q[cur].x], Q[cur].ans = T.QUERY(ID[x], ID[x] + siz[ID[x]] - );
}
else now = ch[now][x], T.add(ID[now], +);
}
}
bool comp(const Query &a, const Query &b) {
return a.ID < b.ID;
}
int main() {
#ifdef WIN32
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
scanf("%s", s + ); N = strlen(s + );
Build();
GetFail();
dfs(root);
Num = read();
for(int i = ; i <= Num; i++) {
int x = read(), y = read();
Q[i] = (Query) {x, y, i};
}
sort(Q + , Q + Num + );
Solve();
sort(Q + , Q + Num + , comp);
for(int i = ; i <= Num; i++)
printf("%d\n", Q[i].ans);
return ;
}

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

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

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

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

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

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

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

  4. BZOJ.2434.[NOI2011]阿狸的打字机(AC自动机 树状数组 DFS序)

    题目链接 首先不需要存储每个字符串,可以将所有输入的字符依次存进Trie树,对于每个'P',记录该串结束的位置在哪,以及当前节点对应的是第几个串(当前串即根节点到当前节点):对于'B',只需向上跳一个 ...

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

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

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

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

  7. bzoj 2434 阿狸的打字机 - Aho-Corasick自动机 - 树状数组

    题目传送门 传送站I 传送站II 题目大意 阿狸有一个打字机,它有3种键: 向缓冲区追加小写字母 P:打印当前缓冲区(缓冲区不变) B:删除缓冲区中最后一个字符 然后多次询问第$x$个被打印出来的串在 ...

  8. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

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

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

随机推荐

  1. Dockerfile常用指令

    FROM 构建的新镜像基于那个镜像 , FROM ubuntu:14 MAINTAINER 镜像维护者姓名或邮箱地址 RUN CMD EXPOSE  声明容器运行服务的端口 ENV ADD  拷贝文件 ...

  2. .Net Core新建解决方案,添加项目引用,使用VSCode调试

    并不是我自己琢磨的,是看了别人学习的,因为写的都不完整,所以就整理一下记录后面忘了回看. 反正.Net Core是跨平台的,就不说在什么系统上了.假设我要建一个名为Doggie的解决方案,里面包含了一 ...

  3. python基础-文件操作(10)

    一.什么是文件 等等这些都叫做文件,各种格式的.但不仅仅限制于这些. 二.文件的作用 大家应该听说过一句话:“好记性不如烂笔头”. 不仅人的大脑会遗忘事情,计算机也会如此,比如一个程序在运行过程中用了 ...

  4. 通过session的id号获取对应的session

    说说为什么要用session!!! 每次访问端通过普通http协议访问tomcat时,访问端包括网页或Android app等,tomcat都会自动生成一个不同的session,而且session的i ...

  5. Python编程Day7——字符编码、字符与字节、文件操作

    一.字符编码 重点 ***** 1. 什么是字符编码:将人识别的字符转换计算机能识别的01,转换的规则就是字符编码表2. 常用的编码表:ascii.unicode.GBK.Shift_JIS.Euc- ...

  6. spring cloud+.net core搭建微服务架构:服务注册(一)

    背景 公司去年开始使用dotnet core开发项目.公司的总体架构采用的是微服务,那时候由于对微服务的理解并不是太深,加上各种组件的不成熟,只是把项目的各个功能通过业务层面拆分,然后通过nginx代 ...

  7. 浅尝Spring Cloud Sleuth

    Spring Cloud Sleuth提供了分布式追踪(distributed tracing)的一个解决方案.其基本思路是在服务调用的请求和响应中加入ID,标明上下游请求的关系.利用这些信息,可以方 ...

  8. 导入项目报错【Minimum supported Gradle version is 3.3. Current version is 2.14.1】

    问题描述 导入项目的时候,因为同事的开发环境是Android Studio 2.3.2  Gradle3.3.而我的开发环境是Android Studio 2.2.2 Gradle2.14.1. 所以 ...

  9. [NewLife.XCode]事务处理(算准你的每一分钱)

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netstandard,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode. 整个系列教程会大量结合示 ...

  10. 简易远程消息交换协议SRMP

    一.SRMP目标定位 经过十多年实战经验积累以及多方共同讨论,新生命团队(https://github.com/newlifex)制订了一种简单而又具有较好扩展性的RPC(Remote Procedu ...