BZOJ 2434 阿狸的打字机 | AC自动机
AC自动机上有神奇的东西叫做fail指针……所有fail指针连起来恰好构成一棵以1为根的树!
而这道题问x在y中出现过多少次,就是问Trie树上根到y的结束节点的路径上有多少节点能通过跳fail跳到x的结束节点上,即,路径上有多少节点在fail树上在x的结束节点的子树中。
那么怎么统计答案呢?可以把询问离线,把fail树DFS一遍得到DFS序列,再把Trie树DFS一遍,DFS到它(入栈)的时候在DFS序列中对应位置+1,离开(出栈)的时候在DFS序列中对应位置-1;中间回答所有当前节点作为y的询问,方法是求对应x的子树和,即序列上的区间和。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 100005;
char s[N];
int n, m, tot = 1, son[N][26], real_son[N][26], fail[N], ans[N];
int st[N], ed[N], idx, adj[N], nxt[N], nod[N], sum[N];
vector <int> num[N];
struct Query {int id, x;};
vector <Query> q[N];
void add(int u, int v){
nxt[v] = adj[u], adj[u] = v;
}
void build(){
static int stk[N], que[N];
int now = 1, len = strlen(s + 1), top = 0, qr;
stk[0] = 1;
for(int i = 1; i <= len; i++)
if(s[i] == 'P') num[now].push_back(++n), nod[n] = now;
else if(s[i] == 'B') now = stk[top = max(0, top - 1)];
else{
int c = s[i] - 'a';
if(!son[now][c]) son[now][c] = ++tot;
now = son[now][c];
stk[++top] = now;
}
for(int i = 1; i <= tot; i++)
for(int j = 0; j < 26; j++)
real_son[i][j] = son[i][j];
for(int i = 0; i < 26; i++) son[0][i] = 1;
que[qr = 1] = 1;
for(int ql = 1; ql <= qr; ql++)
for(int u = que[ql], i = 0; i < 26; i++)
if(!son[u][i]) son[u][i] = son[fail[u]][i];
else{
add(fail[son[u][i]] = son[fail[u]][i], son[u][i]);
que[++qr] = son[u][i];
}
}
void dfs_fail(int u){
st[u] = ++idx;
for(int v = adj[u]; v; v = nxt[v])
dfs_fail(v);
ed[u] = idx;
}
void change(int p, int x){
while(p <= idx) sum[p] += x, p += p & -p;
}
int ask(int p){
int ret = 0;
while(p) ret += sum[p], p -= p & -p;
return ret;
}
void dfs_trie(int u){
change(st[u], 1);
for(vector<int>::iterator i = num[u].begin(); i != num[u].end(); i++)
for(vector<Query>::iterator j = q[*i].begin(); j != q[*i].end(); j++)
ans[j -> id] = ask(ed[nod[j -> x]]) - ask(st[nod[j -> x]] - 1);
for(int i = 0; i < 26; i++)
if(real_son[u][i])
dfs_trie(son[u][i]);
change(st[u], -1);
}
int main(){
scanf("%s", s + 1);
read(m);
for(int i = 1, y; i <= m; i++){
Query tmp;
read(tmp.x), read(y), tmp.id = i;
q[y].push_back(tmp);
}
build();
dfs_fail(1);
dfs_trie(1);
for(int i = 1; i <= m; i++)
write(ans[i]), enter;
return 0;
}
BZOJ 2434 阿狸的打字机 | AC自动机的更多相关文章
- BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)
题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...
- bzoj 2434 阿狸的打字机 - Aho-Corasick自动机 - 树状数组
题目传送门 传送站I 传送站II 题目大意 阿狸有一个打字机,它有3种键: 向缓冲区追加小写字母 P:打印当前缓冲区(缓冲区不变) B:删除缓冲区中最后一个字符 然后多次询问第$x$个被打印出来的串在 ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- AC自动机:BZOJ 2434 阿狸的打字机
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1834 Solved: 1053[Submit][Sta ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
- 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序
[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写 ...
- bzoj 2434 [Noi2011]阿狸的打字机 AC自动机
[Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4001 Solved: 2198[Submit][Status][D ...
- bzoj 2434 [Noi2011]阿狸的打字机——AC自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2434 dfs AC自动机,走过的点权值+1,回溯的时候权值-1:走到询问的 y 串的节点,看 ...
- 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2022 Solved: 1158[Submit][Sta ...
随机推荐
- 通过C# WinForm控件创建的WPF WIndow窗口控件无法输入的问题
原文:通过WinForm控件创建的WPF 控件无法输入的问题 今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在 ...
- Ubuntu 16.04 下部署Node.js+MySQL微信小程序商城
转载于这篇文章 关于pm2看这篇文章 最近在研究小程序,申请了域名之后,再一次来配置环境,根据作者的步骤基本上完成了网站的架构,但由于环境路径等不同,配置上会有所不同,因此记录下来. 1.更新系统和安 ...
- [Spark][Python]RDD flatMap 操作例子
RDD flatMap 操作例子: flatMap,对原RDD的每个元素(行)执行函数操作,然后把每行都“拍扁” [training@localhost ~]$ hdfs dfs -put cats. ...
- gist.github.com 被墙无法访问解决办法
windows下 打开C:\Windows\System32\drivers\etc\hosts文件 编辑器打开,在最后行添加192.30.253.118 gist.github.com 保存.
- Telephone Phrases
There are some common phrases and sentences you can use when speaking on the telephone. The informal ...
- OpenVPN简单部署笔记
打算在IDC机房部署VPN环境,Openvpn也是一个不错的选择:开源,好用,而且免费. OpenVPN简单介绍OpenVPN是一个用于创建虚拟专用网络(Virtual Private Network ...
- C_运算符_逻辑表达式
// 除法取余运算符的例子 //2018年9月19日22:44:21 # include<stdio.h> int main(void) { printf(%, %-, -%, -%-, ...
- 状态模式-State-订单状态
JAVA设计模式-状态模式-State-订单状态 21. State(状态) 意图: 允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类. 解释: 比如说对订单的提交,第一 ...
- 第二个spring,第五天
陈志棚:成绩的统筹 李天麟:界面音乐 徐侃:代码算法 完成进度百分之70...会继续努力的!
- 剑指offer:变态跳台阶
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 思路 首先想到的解决方案是根据普通跳台阶题目改编,因为可以跳任意级,所以要 ...