Portal

Description

首先给出一个只包含小写字母和'B'、'P'的操作序列\(s_0(|s_0|\leq10^5)\)。初始时我们有一个空串\(t\),依次按\(s_0\)的每一位进行操作:

  • 如果是小写字母,则在\(t\)后面加入这个小写字母;
  • 如果是'B',则删除\(t\)的最后一位;
  • 如果是'P',则复制t到集合\(S\)中。

操作结束后,集合中有\(n(n\leq10^5)\)个字符串,将它们按加入集合的顺序标号为\(1..n\)。接下来\(m(m\leq10^5)\)次询问,每次询问串\(x\)在串\(y\)中出现了几次。

Solution

首先根据\(s_0\)我们可以方便的建出一棵Trie树并建立fail指针,记录代表串\(x\)的节点为\(end[x]\)。然后我们就得到了一个fail树:



一个节点在fail树上的祖先就是它的一个后缀,子树就是以该节点作为后缀的串。那么询问就相当于“求\(end[x]\)的子树中,有多少个点在\(root\)到\(end[y]\)的路径上”。

我们求出fail树的DFS序,然后将询问按\(y\)排序。用树状数组维护每个点是否被标记,当\(y\)转移到\(y+1\)时,按照建立Trie树的方法转移。求\(end[x]\)的子树中有多少个被标记的点就相当于求DFS序的区间和。

时间复杂度\(O(nlogn+mlogn)\)。

Code

//[NOI2011]阿狸的打字机
#include <algorithm>
#include <cstdio>
using std::sort;
int const N=1e5+10;
int n; char s0[N];
struct query{int id,x,y,ans;} q[N];
bool cmpY(query x,query y) {return x.y<y.y;}
bool cmpID(query x,query y) {return x.id<y.id;}
int rt,ndCnt,fa[N],ch[N][26],fail[N]; int end[N];
int Q[N],op,cl;
int edCnt,h[N];
struct edge{int v,nxt;} ed[N];
void edAdd(int u,int v)
{
fail[v]=u;
edCnt++; ed[edCnt].v=v,ed[edCnt].nxt=h[u],h[u]=edCnt;
}
void bldFail()
{
for(int i=0;i<26;i++) ch[0][i]=rt;
Q[++cl]=rt;
while(op<cl)
{
int p=Q[++op];
for(int i=0;i<26;i++)
{
int q=ch[p][i];
if(!q) ch[p][i]=ch[fail[p]][i];
else edAdd(ch[fail[p]][i],q),Q[++cl]=q;
}
}
}
int dfCnt,fr[N],to[N];
void dfs(int u)
{
dfCnt++; fr[u]=dfCnt;
for(int i=h[u];i;i=ed[i].nxt) dfs(ed[i].v);
to[u]=dfCnt;
}
int tr[N];
void add(int x,int v) {while(x<=ndCnt) tr[x]+=v,x+=x&(-x);}
int sum(int x) {int r=0; while(x) r+=tr[x],x-=x&(-x); return r;}
int main()
{
scanf("%s",s0+1);
rt=++ndCnt;
for(int i=1,p=rt;s0[i];i++)
{
int x=s0[i]-'a';
if(s0[i]=='B') p=fa[p];
else if(s0[i]=='P') end[++n]=p;
else {if(!ch[p][x]) fa[ch[p][x]=++ndCnt]=p; p=ch[p][x];}
}
bldFail(); for(int i=1;i<=ndCnt;i++) if(!fr[i]) dfs(i);
int m; scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].id=i;
sort(q+1,q+m+1,cmpY);
int now=0,p=rt;
for(int i=0,owo=1,no;owo<=m;owo++)
{
int x=q[owo].x,y=q[owo].y;
while(now<y)
{
i++;
if(s0[i]=='B') add(fr[p],-1),p=fa[p];
else if(s0[i]=='P') now++;
else p=ch[p][s0[i]-'a'],add(fr[p],1);
}
q[owo].ans=sum(to[end[x]])-sum(fr[end[x]]-1);
}
sort(q+1,q+m+1,cmpID);
for(int i=1;i<=m;i++) printf("%d\n",q[i].ans);
return 0;
}

P.S.

双倍经验BZOJ2434

洛谷P2414 - [NOI2011]阿狸的打字机的更多相关文章

  1. 洛谷 P2414 [NOI2011]阿狸的打字机 解题报告

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

  2. 【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解

        这一题是对AC自动机的充分理解和树dfs序的巧妙运用. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和' ...

  3. 洛谷P2414 [NOI2011]阿狸的打字机(AC自动机)

    传送门 考虑一下,如果串B在串A中出现过,那么A的fail指针必定直接或间接指向B 那么我们可以把fail树建起来,那么就变成B代表的节点的子树里有多少节点属于A 然后这就是一个序列统计问题,直接用d ...

  4. P2414 [NOI2011]阿狸的打字机

    P2414 [NOI2011]阿狸的打字机 AC自动机+树状数组 优质题解 <------题目分析 先AC自动机搞出Trie图 然后根据fail指针建一只新树 把树映射(拍扁)到一个序列上,用树 ...

  5. BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...

  6. P2414 [NOI2011]阿狸的打字机 AC自动机

    题意 给定n个模式串,有m个询问,每次询问第X个模式串在第Y个模中出现了多少次 解题思路 以fail树相反的方向建一棵树T,问题转化为X的子树中有多少个y的终止节点.跑出T的dfs序,X的子树就可以表 ...

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

    [NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...

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

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

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

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

随机推荐

  1. 记一次有关spark动态资源分配和消息总线的爬坑经历

    问题: 线上的spark thriftserver运行一段时间以后,ui的executor页面上显示大量的active task,但是从job页面看,并没有任务在跑.此外,由于在yarn mode下, ...

  2. SQL中的SELECT_简单查询语句总结

    --以scott用户下的dept和emp表为例 --注意:如果scott用户不能使用,请使用system用户登录--解锁scott用户ALTER USER SCOTT ACCOUNT UNLOCK;- ...

  3. Android利用已有控件实现自定义控件

    Android控件的基本介绍及使用自定义控件的意义         Android 本身提供了很多控件,自定义控件在android中被广泛运用,自定义控件给了我们很大的方便.比如说,一个视图为imag ...

  4. IE11/Flash页游白屏怎么办!立刻开启IE大地址模式!缓解浏览器白屏问题

    您是否经常发现IE白屏了,具体表现为点开新网页时无法显示,只能切换标签,用任务管理器一看,内存1.2G之多. 这是因为IE11可能有内存泄露问题,内存不断增长以至于无法申请新的内存,于是IE就完蛋了! ...

  5. 伪类的格式重点:父标签层级 & 当前标签类型

    伪类的格式重点:父标签层级 & 当前标签类型 通过例子说明: css1: span:nth-of-type(2){color: red;} css2: span :nth-of-type(2) ...

  6. Halcon学习笔记2

    图像预处理 一般来说,我们采集到的图像会有一些小黑点,小斑点,不平滑等因素会会影响我们后期的算法,此时就需要我们对其图片进行预处理. 下面是一些预处理基本算子: 1.消除噪声:mean_image/b ...

  7. Android(java)学习笔记163:开发一个多界面的应用程序之界面间数据传递

    1.界面跳转的数据传递 (1)intent.setData() --> intent.getData():     传递的数据比较简单,一般是文本类型的数据String:倘若我们传递的数据比较复 ...

  8. Dreamoon and MRT(二元枚举)

    题目 数轴上有M个点a1.a2....am,另有一个数列p1.p2....pn,(1 ≤ pii ≤ M). 给定d1.d2....dn,对所有的 i (1 ≤ i ≤ n),已知 |api+1 - ...

  9. strict说明

  10. 第1节 flume:9、flume的多个agent串联(级联)

    3.两个agent级联 需求分析: 第一个agent负责收集文件当中的数据,通过网络发送到第二个agent当中去,第二个agent负责接收第一个agent发送的数据,并将数据保存到hdfs上面去 第一 ...