BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)
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
3
1 2
1 3
2 3
Sample Output
1
0
HINT
1<=N<=10^5
Source
非常不错的一道题目
首先暴力把每个字符串扔到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自动机 树状数组)的更多相关文章
- [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...
- 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序
[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写 ...
- [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组
[NOI2011] 阿狸的打字机 题目描述: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...
- BZOJ.2434.[NOI2011]阿狸的打字机(AC自动机 树状数组 DFS序)
题目链接 首先不需要存储每个字符串,可以将所有输入的字符依次存进Trie树,对于每个'P',记录该串结束的位置在哪,以及当前节点对应的是第几个串(当前串即根节点到当前节点):对于'B',只需向上跳一个 ...
- BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组
题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...
- BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- bzoj 2434 阿狸的打字机 - Aho-Corasick自动机 - 树状数组
题目传送门 传送站I 传送站II 题目大意 阿狸有一个打字机,它有3种键: 向缓冲区追加小写字母 P:打印当前缓冲区(缓冲区不变) B:删除缓冲区中最后一个字符 然后多次询问第$x$个被打印出来的串在 ...
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
随机推荐
- 机器学习基石笔记:03 Types of Learning
原文地址:https://www.jianshu.com/p/86b2a9cef742 一.学习的分类 根据输出空间\(Y\):分类(二分类.多分类).回归.结构化(监督学习+输出空间有结构): 根据 ...
- 性能调优之Mapping
Mapping层级的调优可能会花费时间,但是性能调优的效果确实非常显著的 优化Target,Source之后,可以调优Mapping 通常的方法是尽可能减少组件及组件的字段间不必要的连线 即尽可能用最 ...
- muduo-ThreadLocal实现细节——阻止销毁未定义对象
muduo利用pthread_key_t实现ThreadLocal模板类. 具体代码如下所示: template<typename T> class ThreadLocal : nonco ...
- win 10 升级远程连接服务器 要求的函数不受支持
首先展示错误信息: win10更新系统后,之前连接的服务器都连接不上了,应该用一下方法解决: 运行 gpedit.msc,打开本地组策略:计算机配置>管理模板>系统>凭据分配> ...
- 使用 SharpZipLib 打包数据到 ZIP 文件
SharpZipLib 是一个优秀的开源的第三方压缩库,可以通过这个库将一些导出的文件打包到一个 ZIP 文件当中供用户下载. GitHub 地址:https://github.com/icsharp ...
- 新生命Redis组件(.Net Core 开源)
NewLife.Redis 是一个Redis客户端组件,以高性能处理大数据实时计算为目标.Redis协议基础实现Redis/RedisClient位于X组件,本库为扩展实现,主要增加列表结构.哈希结构 ...
- Spring Boot 系列 - WebSocket 简单使用
在实现消息推送的项目中往往需要WebSocket,以下简单讲解在Spring boot 中使用 WebSocket. 1.pom.xml 中引入 spring-boot-starter-websock ...
- jvm详情——2、Java对象在jvm中的大小
Java对象的大小 基本数据的类型的大小是固定的,这里就不多说了.对于非基本类型的Java对象,其大小就值得商榷.在Java中,一个空Object对象的大小是8byte,这个大小只是保存堆中一个没有任 ...
- 【原创】深入理解c++的右值引用
0 左值和右值 一个左值表达式代表的是对象本身,而右值表达式代表的是对象的值:变量也是左值. 1 右值引用作用 为了支持移动操作(包括移动构造函数和移动赋值函数),C++才引入了一种新的引 ...
- 在Windows Server 2008 R2上安装IIS服务
一.Windows Server 2008 R2 介绍 1.Windows Server 2008 R2 基本概念 2.Windows Server 2008 R2 家族系列 二.VMware虚拟机安 ...