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'两个字母.经阿狸研究发现, ...
随机推荐
- Python 内置函数介绍
作者博文地址:http://www.cnblogs.com/spiritman/ Python Built-in Functions
- python中取整的几种方法
#encoding:utf-8import math #向上取整print "math.ceil---"print "math.ceil(2.3) => " ...
- python 为什么没有自增自减符
>>> b = 5 >>> a = 5 >>> id(a) 162334512 >>> id(b) 162334512 > ...
- 软件工程 - 第二十次作业 Alpha 事后诸葛亮(团队)
Alpha 事后诸葛亮(团队) 组长本次作业链接:https://www.cnblogs.com/dawnduck/p/10056026.html 现代软件工程 项目Postmortem 设想和目标 ...
- Codeforces Round #345 (Div. 1) C. Table Compression dp+并查集
题目链接: http://codeforces.com/problemset/problem/650/C C. Table Compression time limit per test4 secon ...
- HDU 5501 The Highest Mark
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5501 The Highest Mark Accepts: 32 Submissions: 193 ...
- mysql的程序组成
MySQL的程序组成 1:客户端 mysql:客户端程序 mysqldump:mysql备份工具 mysqladmin:mysql管理工具 mysqlbinlog:二进制日志查询工具 2:服务端 my ...
- python 将base64字符串还原为图片
今天弄验证码的时候发现,验证码的图片的src竟然是下面的这么一个一串字符串,吓到,好像不可以http请求的,第一次见,就好尴尬,去网上搜索了一下,说是: 这是Data URI scheme. data ...
- 更改HTTP头信息
http信息分三部分 1.请求行 GET lizi.php HTTP/1.1 2.HTTP头信 Host: localhost Connection: keep-alive Cache-Contr ...
- Post/Redirect/Get
参考地址:https://www.cnblogs.com/TonyYPZhang/p/5424201.html 参考资料:Flask Web开发:基于Python的Web应用开发实战 Post/Red ...