题目大意:

http://www.lydsy.com/JudgeOnline/problem.php?id=2434

题解:

首先我们可以发现这个打字的过程本身就是在Trie上滚来滚去的过程

所以我们可以直接根据这个建树

然后构建出fail树后我们考虑如何处理询问

对于任意一个询问(x,y)我们都可以统计从y到root的节点上有多少指向x的fail

但是这样肯定超时

所以反向考虑x的所有指向x的fail,和指向指向x的fail的fail... ...

我们把所有的fail反响建出一颗树来

这时候我们发现以x为根的子树即为所有直接或间接指向x的fail(反转前)

所以我们统计一下这可子树中有多少y即可

所以可以树套树解决

我们发现我们可以直接离线树状数组瞎搞

我们直接重复一遍打印的过程,把当前在凹槽中的字符对应的fail树的dfs序上+1

离线询问后直接查询即可

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
int ch[maxn][26],nodecnt,fa[maxn];
int val[maxn];
char str[maxn];
struct Edge{
int to,next;
}G[maxn];
int head[maxn],cnt;
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
int q[maxn],l,r,f[maxn];
inline void build(){
f[0] = 0;l = 0;r = -1;
int u = 0;
for(int c=0;c<26;++c){
if(ch[u][c]){
f[ch[u][c]] = 0;
q[++r] = ch[u][c];
}
}
while(l <= r){
u = q[l++];
for(int c=0;c<26;++c){
int v = ch[u][c];
if(!v){
ch[u][c] = ch[f[u]][c];
continue;
}q[++r] = v;
int x = f[u];
while(x && !ch[x][c]) x = f[x];
f[v] = ch[x][c];
}
}
}
int ind[maxn],oud[maxn],dfs_clock = -1;
#define v G[i].to
inline void dfs(int u){
ind[u] = ++ dfs_clock;
for(int i = head[u];i;i=G[i].next) dfs(v);
oud[u] = dfs_clock;
}
#undef v
struct Node{
int x,y,id;
bool friend operator < (const Node &a,const Node &b){
return a.y < b.y;
}
}a[maxn];
int anss[maxn];
int c[maxn],num;
#define lowbit(x) (x&-x)
inline void modify(int x,int y){
for(;x<=dfs_clock + 10;x += lowbit(x)) c[x] += y;
}
inline int query(int x){
int ret = 0;
for(;x;x-=lowbit(x)) ret += c[x];
return ret;
}
int mp[maxn];
int main(){
scanf("%s",str);
int n = strlen(str);
int nw = 0;
for(int i=0;i<n;++i){
if(str[i] == 'P') val[nw] = ++num,mp[num] = nw;
else if(str[i] == 'B') nw = fa[nw];
else{
int c = str[i] - 'a';
if(ch[nw][c] == 0){
ch[nw][c] = ++nodecnt;
fa[nodecnt] = nw;
}nw = ch[nw][c];
}
}build();
for(int i=nodecnt;i>=1;--i) add(f[i],i);
dfs(0);
int m;read(m);
for(int i=1;i<=m;++i){
read(a[i].x);
read(a[i].y);
a[i].id = i;
}sort(a+1,a+m+1);
nw = 0;int p = 1,cnt_p = 0;
for(int i=0;i<n;++i){
if(str[i] == 'P'){
++ cnt_p;
while(a[p].y == cnt_p){
anss[a[p].id] = query(oud[mp[a[p].x]])-query(ind[mp[a[p].x]]-1);
++p;
}
}else if(str[i] == 'B'){
modify(ind[nw],-1);
nw = fa[nw];
}else{
int c = str[i] - 'a';
nw = ch[nw][c];
modify(ind[nw],1);
}
}
for(int i=1;i<=m;++i) printf("%d\n",anss[i]);
getchar();getchar();
return 0;
}

bzoj 2434: 阿狸的打字机 fail树+离线树状数组的更多相关文章

  1. bzoj 2434 阿狸的打字机 fail树的性质

    如果a串是另b串的后缀,那么在trie图上沿着b的fail指针走一定可以走到a串. 而a串在b串里出现多少次就是它是多少个前缀的后缀. 所以把fail边反向建树维护个dfs序就行了. 并不是很难... ...

  2. BZOJ 2434 阿狸的打字机(fail树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2434 题意:阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28 ...

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

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

  4. BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)

    题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...

  5. AC自动机:BZOJ 2434 阿狸的打字机

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

  6. [NOI 2011][BZOJ 2434] 阿狸的打字机

    传送门 AC自动机 + 树状数组 建成AC自动机后,设end[i]为第i个串的末尾在Trie树上的节点. 可以发现,对于一个询问(x,y),ans等于Trie树上root到end[y]这条链上fail ...

  7. BZOJ 2434 阿狸的打字机

    http://www.lydsy.com/JudgeOnline/problem.php?id=2434 思路:建立fail树,并找出dfs序,那剩下要做的就是每次找到一个串的位置,然后询问它的区间里 ...

  8. BZOJ 2434 阿狸的打字机 | AC自动机

    题目戳这里 AC自动机上有神奇的东西叫做fail指针--所有fail指针连起来恰好构成一棵以1为根的树! 而这道题问x在y中出现过多少次,就是问Trie树上根到y的结束节点的路径上有多少节点能通过跳f ...

  9. 【BZOJ 2434】【NOI 2011】阿狸的打字机 fail树

    完全不会啊,看题解还看了好久,我是蒟蒻$QAQ$ $zyf$的题解挺好的:http://blog.csdn.net/clove_unique/article/details/51059425 $fai ...

随机推荐

  1. 浅谈<持续集成、持续交付、持续部署>(一)

    谈谈持续集成,持续交付,持续部署之间的区别 经常会听到持续集成,持续交付,持续部署,三者究竟是什么,有何联系和区别呢?   假如把开发工作流程分为以下几个阶段: 编码 -> 构建 -> 集 ...

  2. [原创]使用vscode+es6写nodejs服务端调试配置

    前端的小伙伴们在babel等的加持下,已经可以愉快的使用es6来写代码了. 然后对于服务端的nodejs就有点坑爹了,虽然原生支持了es6,但是只是部分支持,一些不支持的特性(比如module)使用了 ...

  3. 九度OJ 1200:最大的两个数 (最值)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2904 解决:761 题目描述: 输入一个四行五列的矩阵,找出每列最大的两个数. 输入: 输入第一行包括一个整数n(1<=n<= ...

  4. 使用memcache进行账号验证服务

    适用环境是需要频繁进行账号和请求合法性验证的地方 大致思路: 1.登陆时,服务器端接收一个账号和密码,还可以再加上用户的ip等信息通过md5等加密算法计算出一个定长的字符串作为用来验证的token 2 ...

  5. Spring 拦截器——HandlerInterceptor

    采用Spring拦截器的方式进行业务处理.HandlerInterceptor拦截器常见的用途有: 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等. 2 ...

  6. 感知器(Perception)

    感知器是一种早期的神经网络模型,由美国学者F.Rosenblatt于1957年提出.感知器中第一次引入了学习的概念,使人脑所具备的学习功能在基于符号处理的数学到了一定程度模拟,所以引起了广泛的关注. ...

  7. Java并发之LinkedBlockingQueue

    上一篇我们已经学习过了 ArrayBlockingQueue的知识及相关方法的使用,这一篇我们就来再学习一下ArrayBlockingQueue的亲戚 LinkedBlockingQueue.在集合类 ...

  8. C#实例,熟练使用泛型数组等,课程选择小软件

    CourseItem.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; ...

  9. php匹配字符串中大写字母的位置

    变量名用的是驼峰,数据库中字段中的是下划线,现在想把userId等变量批量转换成user_id,怎么样获取大写字母在字符串中的位置?echo strtolower(preg_replace('/((? ...

  10. 【leetcode刷题笔记】Evaluate Reverse Polish Notation

    Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...