bzoj 2434 AC自动机+树状数组
2434: [Noi2011]阿狸的打字机
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 3493 Solved: 1909
[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
代码:
//先把字符串直接建AC自动机,有删除操作'B'所以记一下父节点。val[i]数组记录第i个单词在字典树中的位置,我们知道x
//在y中出现的次数就是y中有多少个fail指向x的结尾字符,我们把fail反向就可以看做一棵树,x在y中出现的位置一定是
//fail树的dfs序列中连续的一段,然后我们就可以用离线树状数组处理。处理出fail树的dfs序作(每个点有两个端点出和入)
//为树状数组的点,按照y从小到大排序,然后按照字符串s的顺序加入字符时在该节点对应的dfs序的点+1,删除字符时-1,
//当遇到y节点时就求出所有的与此y节点相关的询问这样按照y递增的顺序来求小的y就不会对大的y有影响了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=;
int m,node[MAXN+][],f[MAXN+],val[MAXN+],sz;
int head[MAXN+],tot,pre[MAXN+],N,in[MAXN+],out[MAXN+],ans[MAXN+],A[MAXN*+];
char s[MAXN+];
struct Lu
{
int x,y,id;
bool operator < (const Lu &p)const{
return y<p.y;
}
}L[MAXN+];
struct Edge { int to,next; }edge[MAXN*+];
void init()
{
sz=tot=N=;
memset(node[],,sizeof(node[]));
f[]=val[]=;
memset(A,,sizeof(A));
memset(head,-,sizeof(head));
}
void add_edge(int x,int y)
{
edge[tot].to=y;
edge[tot].next=head[x];
head[x]=tot++;
edge[tot].to=x;
edge[tot].next=head[y];
head[y]=tot++;
}
void insert(char *s)
{
int len=strlen(s),rt=,cnt=;
for(int i=;i<len;i++){
if(s[i]=='B') { rt=pre[rt];continue; }
else if(s[i]=='P') { val[++cnt]=rt;continue; }
int id=s[i]-'a';
if(!node[rt][id]){
node[rt][id]=++sz;
pre[sz]=rt;
memset(node[sz],,sizeof(node[sz]));
val[sz]=;
}
rt=node[rt][id];
}
}
void get_fail()
{
queue<int>q;
for(int i=;i<;i++){
int u=node[][i];
if(u) { q.push(u);f[u]=; }
}
while(!q.empty()){
int rt=q.front();q.pop();
add_edge(rt,f[rt]);
for(int i=;i<;i++){
int u=node[rt][i];
if(!u){
node[rt][i]=node[f[rt]][i];
continue;
}
q.push(u);
f[u]=node[f[rt]][i];
//add_edge(u,f[u]);
}
}
}
void dfs(int x,int fa)
{
in[x]=++N;
for(int i=head[x];i!=-;i=edge[i].next){
int y=edge[i].to;
if(y==fa) continue;
dfs(y,x);
}
out[x]=N;
}
void add(int id,int c)
{
while(id<=MAXN){
A[id]+=c;
id+=(id&-id);
}
}
int query(int id)
{
int ss=;
while(id){
ss+=A[id];
id-=(id&-id);
}
return ss;
}
void solve(char *s)
{
int len=strlen(s),cnt=,rt=,j=;
for(int i=;i<len;i++){
if(s[i]=='B'){
add(in[rt],-);
rt=pre[rt];
}
else if(s[i]=='P'){
cnt++;
while(j<m&&L[j].y==cnt){
ans[L[j].id]=query(out[val[L[j].x]])-query(in[val[L[j].x]]-);
j++;
}
}else{
rt=node[rt][s[i]-'a'];
add(in[rt],);
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
init();
scanf("%s",s);
scanf("%d",&m);
for(int i=;i<m;i++){
scanf("%d%d",&L[i].x,&L[i].y);
L[i].id=i;
}
sort(L,L+m);
insert(s);
get_fail();
dfs(,-);
solve(s);
for(int i=;i<m;i++) printf("%d\n",ans[i]);
return ;
}
bzoj 2434 AC自动机+树状数组的更多相关文章
- 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序
[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写 ...
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- BZOJ.2434.[NOI2011]阿狸的打字机(AC自动机 树状数组 DFS序)
题目链接 首先不需要存储每个字符串,可以将所有输入的字符依次存进Trie树,对于每个'P',记录该串结束的位置在哪,以及当前节点对应的是第几个串(当前串即根节点到当前节点):对于'B',只需向上跳一个 ...
- BZOJ 3881 [Coci2015]Divljak(AC自动机+树状数组)
建立AC自动机然后,加入一个串之后考虑这个串的贡献.我们把这个串扔到AC自动机里面跑.最后对经过每一个点到的这个点在fail树的根的路径上的点有1的贡献.求链的并,我们把这些点按DFS序排序,然后把每 ...
- [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...
- BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4140 Solved: 2276[Submit][Status][Discuss] Descript ...
- BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- HDU 6096 String(AC自动机+树状数组)
题意 给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠. \(1 \leq ...
- [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组
[NOI2011] 阿狸的打字机 题目描述: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...
随机推荐
- IO多路复用(二) -- select、poll、epoll实现TCP反射程序
接着上文IO多路复用(一)-- Select.Poll.Epoll,接下来将演示一个TCP回射程序,源代码来自于该博文https://www.cnblogs.com/Anker/p/3258674.h ...
- 从零开始的Python学习Episode 9——集合
集合 集合是一个无序的,不重复的数据组合,是python基本的数据类型,把不同的元素组成一起就形成集合. 一.创建集合 s = set('smile')list = ['1','2','3']prin ...
- New begin
Purpose 今天更换了id,希望重新沉淀. 晚上看到国外一个博客,落款有个中文: 敬惜字纸. 共勉.
- loadrunner socket协议问题归纳(1)
前段时间测了loadrunner直接发送报文到socket上的性能测试.在此,稍微回顾整理下. 与socket通讯,有两种方式,一种是建立长连接,建立后,不停的发送,接收.另外一种是建立短连接,建立连 ...
- 0329--Scrum团队准备工作
一.团队名称,团队目标.团队口号.团队照 1.团队名称:Blackhriar 2.团队目标:完成一个完善的,可以投入市场供用户使用,甚至具有一定商业价值的项目~come on! 3.团队口号:抱怨事件 ...
- 第一个scrum会议
第一阶段冲刺任务认领: PM薛哥: 让手电筒亮起来 梁哥: 代码测试 康哥: 用户反馈等等
- MacOS下安装Requests库及使用
大概框架 Request库的安装 爬取网页最好用的第三方库 直接安装即可(用于OS X) pip3 install requests request库的常用方法: request库一共有七个常用方法. ...
- (工具类)MD5算法|时间格式转换|字符串转数字
package vote.utils; import java.security.MessageDigest; import java.text.SimpleDateFormat; import ja ...
- net项目调试时,读取主干或其他项目代码问题
最近调试项目的时候出了一个很奇怪的问题. 项目总是去读取另外一个项目的配置文件,甚至执行的代码都是另外一个项目的. 我用vs修改代码时候,甚至修改到了其他项目的代码,生成不报错,很奇怪. 本来怀疑是v ...
- JarvisOJ平台Web题部分writeup
PORT51 题目链接:http://web.jarvisoj.com:32770/ 这道题本来以为是访问服务器的51号端口,但是想想又不太对,应该是本地的51号端口访问服务器 想着用linux下的c ...