题目这么说的:

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。
经阿狸研究发现,这个打字机是这样工作的:

  1. 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
  2. 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
  3. 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

  • 把AC自动机的结点作为树结点,将fail指针的方向取反设为树边,这样除了AC自动机头结点外每个结点都有且仅有一条进入它的边,这样就得到一棵叫fail树的树。
  • 在AC自动机中如果y的fail指针指向x,可知x表示的字符串前缀是y结点表示的字符串前缀的后缀;因此可以知道在fail树中x为根的子树的所有结点表示的字符串前缀都包含x结点所表示的字符串前缀。
  • 对于,询问一个字符串x在另一个字符串y出现了多少次,就可以这样:在fail树中标记字符串y的所有前缀结点,然后看x为根的子树有多少个被标记结点就是答案,这个可以用DFS序+线段树实现。
  • 而对于这题的具体实现:
    1. 首先可以顺着输入的字符串序列B往父亲走,P标记这样建立AC自动机
    2. 然后把查询离线处理,用邻接表记录每一组查询<x,y>中每个y有哪几个x
    3. 最后再顺着输入的字符串序列,遇到B和小写字符更新线段树,遇到P去查询出当前y的所有x的答案
 #include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXN 111111 struct Edge{
int v,next;
}edge[MAXN];
int NE,head[MAXN];
void addEdge(int u,int v){
edge[NE].v=v; edge[NE].next=head[u];
head[u]=NE++;
} int tn,ch[MAXN][],fa[MAXN],flag[MAXN],fail[MAXN];
int belong[MAXN],bn,rbelong[MAXN];
char str[];
void insert(){
int x=;
for(int i=; str[i]; ++i){
if(str[i]=='B'){
x=fa[x];
}else if(str[i]=='P'){
flag[x]=;
belong[x]=++bn;
rbelong[bn]=x;
}else{
int y=str[i]-'a';
if(ch[x][y]==) ch[x][y]=++tn,fa[ch[x][y]]=x;
x=ch[x][y];
}
}
}
void getfail(){
queue<int> que;
for(int i=; i<; ++i){
if(ch[][i]){
que.push(ch[][i]);
addEdge(,ch[][i]);
}
}
while(!que.empty()){
int x=que.front(); que.pop();
for(int i=; i<; ++i){
if(ch[x][i]){
que.push(ch[x][i]);
fail[ch[x][i]]=ch[fail[x]][i];
addEdge(fail[ch[x][i]],ch[x][i]);
}else ch[x][i]=ch[fail[x]][i];
}
}
} int dfn,l[MAXN],r[MAXN],par[MAXN];
void dfs(int u){
l[u]=++dfn;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
par[v]=u;
dfs(v);
}
r[u]=dfn;
} int tree[MAXN<<],N,x,y;
void update(int i,int j,int k){
if(i==j){
tree[k]+=y;
return;
}
int mid=i+j>>;
if(x<=mid) update(i,mid,k<<);
else update(mid+,j,k<<|);
tree[k]=tree[k<<]+tree[k<<|];
}
int query(int i,int j,int k){
if(x<=i && j<=y){
return tree[k];
}
int mid=i+j>>,res=;
if(x<=mid) res+=query(i,mid,k<<);
if(y>mid) res+=query(mid+,j,k<<|);
return res;
} struct Query{
int x,y,ans,next;
}que[MAXN];
int qhead[MAXN],qNE,order[MAXN];
void addQuery(int x,int y){
que[qNE].x=x; que[qNE].y=y; que[qNE].next=qhead[y];
qhead[y]=qNE++;
} void doit(){
int now=;
for(int i=; str[i]; ++i){
if(str[i]=='B'){
x=l[now]; y=-;
update(,N,);
now=fa[now];
}else if(str[i]=='P'){
for(int j=qhead[belong[now]]; j!=-; j=que[j].next){
x=l[rbelong[que[j].x]]; y=r[rbelong[que[j].x]];
que[j].ans=query(,N,);
}
}else{
now=ch[now][str[i]-'a'];
x=l[now]; y=;
update(,N,);
}
}
}
int main(){
scanf("%s",str);
insert();
memset(head,-,sizeof(head));
getfail();
dfs();
for(N=; N<dfn; N<<=);
memset(qhead,-,sizeof(qhead));
int m,a,b;
scanf("%d",&m);
for(int i=; i<m; ++i){
scanf("%d%d",&a,&b);
order[i]=qNE;
addQuery(a,b);
}
doit();
for(int i=; i<m; ++i){
printf("%d\n",que[order[i]].ans);
}
return ;
}

BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)的更多相关文章

  1. BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  2. BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组

    题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...

  3. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

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

  4. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

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

  5. BZOJ2434: [Noi2011]阿狸的打字机(AC自动机 树状数组)

    Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4140  Solved: 2276[Submit][Status][Discuss] Descript ...

  6. [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...

  7. BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  8. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  9. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

随机推荐

  1. Mysql事务隔离级别

    在说Isolation之前,需要谈谈关系型数据库的ACID特性. A(atomicity,原子性),指一个事务要么完全完成,要么全部回滚到起始状态,不存在中间状态. C(Consistency,一致性 ...

  2. NYOJ题目57 6174问题

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAscAAAJLCAIAAACE5qzaAAAgAElEQVR4nO3dMXKrutvH8XcT6bOQ1C ...

  3. poj 3461Oulipo

    题目链接:http://poj.org/problem?id=3461 统计字符串出现的次数 #include<cstdio> #include<iostream> #incl ...

  4. 三、jQuery--jQuery基础--jQuery基础课程--第5章 jQuery 操作DOM元素

    1.使用attr()方法控制元素的属性 attr()方法的作用是设置或者返回元素的属性,其中attr(属性名)格式是获取元素属性名的值,attr(属性名,属性值)格式则是设置元素属性名的值. 例如,使 ...

  5. SESSION机制

    一:Session与Cookie Session:在服务器端创建并存放在服务器的内存中的,Session的内容存储是键值对的列表,格式:名称 | 类型:长度:值 Session的生命周期:在php.i ...

  6. redis-cli -h xxxxx -p xxxx monitor 监控host为xxxx,端口为xxx,redis连接及读写操作

    # redis-cli -p monitor OK ] " lua] " lua] " "-1"

  7. 与你相遇好幸运,Sails.js自定义数据库名

    在/api/models/下,自定义的.js文件内容 module.exports = { tableName: '自定义的数据库名',  autoCreatedAt: false, //关闭  au ...

  8. PHP实现执行定时任务的几种思路详解

    转:https://segmentfault.com/a/1190000002955509 PHP本身是没有定时功能的,PHP也不能多线程.PHP的定时任务功能必须通过和其他工具结合才能实现,例如Wo ...

  9. HTML5学习之WebWork多线程处理(八)

    多线程技术在服务端技术中已经发展的很成熟了,而在Web端的应用中却一直是鸡肋 在新的标准中,提供的新的WebWork API,让前端的异步工作变得异常简单. 使用:创建一个Worker对象,指向一个j ...

  10. 验证备份前设置CONFIGURE CONTROLFILE AUTOBACKUP ON/OFF; 的区别

    关于rman的,环境: oracle 10.2.0 rman nocatalog方式 1.首先设置 CONFIGURE CONTROLFILE AUTOBACKUP ON; 然后进行数据库全备份 RM ...