【题目大意】

输入一个字符串,其中:(1)a..z:在字符串末尾添加当前字符(2)P:输出当前字符串(3)B:从当前字符串末尾删去一个字符。

给出m组查询,输出第i个输出的字符串在第j个输出的字符串内出现了几次。

【思路】

卡了好久,写完不想调试,调试完不想提交,期间颓颓颓地弄了下博客的界面,弄成了粉嫩少女风(划掉)。结果提交完1A有点迷醉迷醉的……

首先我们要借用BZOJ3172的结论:←戳这里,这个结论66666,是本次解题的关键。

“建立AC自动机,对于路径上的每一个点sum++,表示出现的次数。fail指针指向的后缀,如果从fail指针指向的点开始方向建立fail树,其子树的sum之和就等于以它作为后缀的串的总数,相当于它在文章中出现的个数。”

显然我们要把m组询问(i,j)调换位置,同一组j,对i建立一个链表存放。为什么要这么做呢?先继续往下看。

首先,我们建立一个AC自动机,并建立fail树。这里和一般的建立有点区别,因为有删除操作,可以用一个栈来维护当前位于Trie的位置,如果B删除就弹出栈顶,如果为字母就建立新节点并压入栈中,如果是P就在当前位置打上ed的标记,表示这是第ed次打印的字符终止位置。

由于树中节点和子树的dfs序是连续的,我们跑一次dfs记录下fail树上每个点的dfs序,记录下第i个输出字符串,它的末尾节点及其子树在dfs序中的start和end位置。

最后,重新跑一次Trie,和先前一样用栈维护。如果遇到B,就将当前节点-1,弹出栈顶;遇到字母就将当前节点+1;如果遇到P,说明现在恰巧输出了第j个字符串,枚举每一个查询中的i,查询结果=当前i对应的节点和它子树之和。

没错,这是一个单点修改,区间求和,可以用树状数组来维护一下,每个节点在树状数组中的位置就等于它的dfs序。那么当前i对应的节点及其子树之和=sum[start[i]..end[i]],搞定!

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define lnum 26
using namespace std;
const int MAXN=+;
int ppos[MAXN];//第i个P对应的栈顶位置编号
char str[MAXN];
int m,len,step,cnt=,e[MAXN],start[MAXN],end[MAXN],ans[MAXN];
struct ACauto
{
ACauto* next[lnum];
ACauto* fail;
int id,ed,order;
ACauto()
{
for (int i=;i<lnum;i++) next[i]=NULL;
fail=NULL;
id=++cnt;
}
};
struct node
{
int to,id;
};
ACauto* rt=new ACauto();
ACauto* p[MAXN];//编号为i的节点指向的位置
vector<node> Q[MAXN];
vector<int> E[MAXN]; void addedge(int u,int v)
{
E[u].push_back(v);
} int lowbit(int x)
{
return (x&(-x));
} void modify(int p,int x)
{
int i=p;
while (i<=len)
{
e[i]+=x;
i+=lowbit(i);
}
} int sum(int p)
{
int s=;
int i=p;
while (i>)
{
s+=e[i];
i-=lowbit(i);
}
return s;
} void init()
{
scanf("%s",str);
len=strlen(str);
int top=,n=;
ACauto* stack[MAXN];
stack[++top]=p[]=rt;//不要忘记给p[1]赋值
for (int i=;i<len;i++)
{
if (str[i]=='P')
{
stack[top]->ed=++n;
ppos[n]=stack[top]->id;
}
else if (str[i]=='B') top--;
else
{
int index=str[i]-'a';
if (stack[top]->next[index]==NULL)
{
stack[top]->next[index]=new ACauto();
p[cnt]=stack[top]->next[index];
}
stack[++top]=stack[top-]->next[index];
}
} scanf("%d",&m);
for (int i=;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
Q[y].push_back((node){ppos[x],i});
}
} void buildfail()
{
queue<ACauto*> que;
que.push(rt);
while (!que.empty())
{
ACauto* head=que.front();que.pop();
for (int i=;i<lnum;i++)
{
if (head->next[i]!=NULL)
{
if (head==rt)
{
head->next[i]->fail=rt;
addedge(rt->id,head->next[i]->id);
}
else
{
ACauto* tmp=head->fail;
while (tmp!=NULL)
{
if (tmp->next[i]!=NULL)
{
head->next[i]->fail=tmp->next[i];
addedge(tmp->next[i]->id,head->next[i]->id);
break;
}
else tmp=tmp->fail;
}
if (tmp==NULL)
{
head->next[i]->fail=rt;
addedge(rt->id,head->next[i]->id);
}
}
que.push(head->next[i]);
}
}
}
} void dfs(int pos)
{
ACauto* tmp=p[pos];
tmp->order=++step;
if (tmp->ed) start[tmp->ed]=step;
for (int i=;i<E[pos].size();i++) dfs(E[pos][i]);
if (tmp->ed) end[tmp->ed]=step;
} void query()
{
memset(e,,sizeof(e));
int top=,n=;
ACauto* stack[MAXN];
stack[++top]=rt;
for (int i=;i<len;i++)
{
if (str[i]=='P')
{
n++;
for (int i=;i<Q[n].size();i++)
{
ACauto* to=p[Q[n][i].to];
ans[Q[n][i].id]=sum(end[to->ed])-sum(start[to->ed]-);
}
}
else if (str[i]=='B')
{
modify(stack[top]->order,-);
top--;
}
else
{
int index=str[i]-'a';
stack[++top]=stack[top-]->next[index];
modify(stack[top]->order,);
}
}
} void printans()
{
for (int i=;i<m;i++) printf("%d\n",ans[i]);
} int main()
{
init();
buildfail();
dfs(rt->id);
query();
printans();
return ;
}

【dfs序+AC自动机+树状数组】BZOJ2434-[Noi2011]阿狸的打字机的更多相关文章

  1. 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序

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

  2. BZOJ.2434.[NOI2011]阿狸的打字机(AC自动机 树状数组 DFS序)

    题目链接 首先不需要存储每个字符串,可以将所有输入的字符依次存进Trie树,对于每个'P',记录该串结束的位置在哪,以及当前节点对应的是第几个串(当前串即根节点到当前节点):对于'B',只需向上跳一个 ...

  3. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

  4. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  5. 洛谷P2414 阿狸的打字机【AC自动机】【fail树】【dfs序】【树状数组】

    居然真的遇上了这种蔡队题.瑟瑟发抖. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿 ...

  6. CoderForces 163E e-Government(AC自动机+树状数组维护fail树的dfs序)

    E. e-Government time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

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

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

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

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

  9. HDU 6096 String(AC自动机+树状数组)

    题意 给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠. \(1 \leq ...

随机推荐

  1. 在ubuntu16.04+python3.5情况下安装nltk,以及gensim时pip3安装不成功的解决办法

    在ubuntu16.04+python3.5情况下安装nltk,以及gensim时pip3安装不成功的解决办法,我刚开始因为不太会用linux命令,所以一直依赖于python 的pip命令,可是怎么都 ...

  2. python 实现二叉树相关算法

    一.构建与遍历二叉树 基本性质 1)在二叉树的第i层上最多有2i-1 个节点 .(i>=1)2)二叉树中如果深度为k,那么最多有2k-1个节点.(k>=1)3)在完全二叉树中,具有n个节点 ...

  3. GBK UTF-16 UTF-8 编码表

    GBK   UTF-16 UTF-8 ================== D2BB  4E00  E4 B8 80  一 B6A1  4E01  E4 B8 81  丁 C6DF  4E03  E4 ...

  4. 数字签名算法rsa

    数字签名算法消息传递模型 由消息发送方构建密钥对,这里由甲方完成. 由消息发送方公布公钥至消息接收方,这里由甲方将公钥公布给乙方. 注意如加密算法区别,这里甲方使用私钥对数据签名,数据与签名形成一则消 ...

  5. sublime在搜索的时候排除js文件

    代码审计的时候sublime是一个神器.所以.... Ctrl + Shift + F /home/i3ekr/Desktop/coding/phpcms,*.php 这样就可以直接搜索所有的php文 ...

  6. [New learn]AutoLayout调查基于IB

    代码:https://github.com/xufeng79x/AutoLayout-IB 1.简介 Autolayout旨在解决不同高宽度的屏幕下的显示问题,通过增加给控件增加约束来达到不同屏幕间的 ...

  7. [New learn]SDWebImage框架的基本使用

    代码:https://github.com/xufeng79x/SDWebImage 1.简介 SDWebImage是一个第三方框架,它能够帮助我们有效管理应用图片下载,沙盒保存和内存保存的任务.通过 ...

  8. mongodb循环

     var rds = db.REGIPATIENTREC.find({mzh:{$lt:"0"},usrOrg:"石景山中西医结合医院"}); var show ...

  9. Linux网络属性配置命令和管理详解

    一.Linux网络属性配置 1.Linux主机接入到网络方式 IP/NETMASK:实现本地网络通信 路由(网关):可以进行跨网络通信 DNS服务器地址:基于主机名的通信,Linux可以有三个DNS地 ...

  10. 小程序css

    样式导入 @import /** common.wxss **/ .small-p { padding:5px; } /** app.wxss **/ @import "common.wxs ...