阿狸的打字机

\(\text{Solution:}\)

首先观察三种操作:一种是插入一个字符,一种是退回上一步(回到父亲节点)。

所以,我们可以对操作串进行模拟,并处理出每一个串在树上的位置。

接下来,我们考虑如何处理询问。\(y\)是需要跑的串,于是我们应按照\(y\)排序以保证在处理这个\(y\)之前,它本身或者其他的东西没有加进树上过。

考虑同样的模板处理方法:对于一个串出现了几次,我只需要统计这个串结尾编号在\(fail\)树子树中的\(cnt\)个数。

于是自然想到维护子树和的有利武器:\(dfs\)序和树状数组。

于是,我们可以预先处理掉\(dfs\)序,并直接模拟在\(opt\)串上进行的移动操作即可。

这里解释模板的处理思路:首先,既然我们跳到了这个\(fail\)指针,说明我们一定匹配完过当前这整个\(fail\)指针(参考定义)。

观察\(fail\)树上的结构,我们结合上面所述可以知道,所有直接或间接指向\(x\)这个节点的\(fail\)指针,只要跳到了,就一定匹配到过整个串\(x\).

于是,我们可以统计\(fail\)树上\(x\)子树中的\(cnt\),注意每匹配到一个点,应该在\(fail\)树上把从它到根节点的路径上全部加\(1.\)但实际上我们只需要在匹配到的时候对它单点\(+1,\)再\(dfs\)一下\(fail\)树就可以了。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2000100;
int tot,tr[MAXN],fa[MAXN];
int pos[MAXN],num;
struct Tree{
int ch[26],fail;
}T[MAXN];
vector<int>to[MAXN];
struct Qu{
int x,y,id;
}Q[MAXN];
inline bool cmp(Qu a,Qu b){return a.y<b.y;}
char opt[MAXN];
void Build(char *s,int L){
int u=0;
for(int i=0;i<L;++i){
if(opt[i]=='B')u=fa[u];
else if(opt[i]=='P')pos[++num]=u;
else if(T[u].ch[s[i]-'a'])u=T[u].ch[s[i]-'a'];
else T[u].ch[s[i]-'a']=++tot,fa[tot]=u,u=tot;//介于本题需要有跳回上一步的操作,所以需要记录一下fa
}
//对操作串进行处理,并记录下每一个询问串在树上的位置
}
void bfs(){
queue<int>q;
for(int i=0;i<26;++i){
if(T[0].ch[i]){
int v=T[0].ch[i];
T[v].fail=0;
q.push(v);
}
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;++i){
if(T[u].ch[i]){
int v=T[u].ch[i];
T[v].fail=T[T[u].fail].ch[i];
q.push(v);
}
else T[u].ch[i]=T[T[u].fail].ch[i];
}
to[T[u].fail].push_back(u);
}
//建立AC自动机并建立fail树
}
int dfn[MAXN],I,ed[MAXN];
void dfs(int u){
dfn[u]=++I;
for(int i=0;i<to[u].size();++i)dfs(to[u][i]);
ed[u]=I;
//处理出每一个树上节点的dfs序列,注意是树上的
}
inline int lowbit(int x){return (x&(-x));}
inline void add(int x,int v){for(;x<=I;x+=lowbit(x))tr[x]+=v;}
inline int query(int x){int res=0;for(;x;x-=lowbit(x))res+=tr[x];return res;}
//树状数组不解释
int ans[MAXN],m;
int main(){
scanf("%s",opt);
int len=strlen(opt);
Build(opt,len);
bfs();dfs(0);
//预处理
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,cmp);//按照询问的y从小到大处理
int u=0,r=0,l=0;
for(int i=1;i<=m;++i){
while(r<Q[i].y){
if(opt[l]=='P')r++;//更新目前处理到第几个串
else if(opt[l]=='B'){
add(dfn[u],-1);
u=fa[u];
}//删掉当前u所在字符
else{
u=T[u].ch[opt[l]-'a'];
add(dfn[u],1);
}//更新下一个字符
l++;//操作串后移
}
ans[Q[i].id]=query(ed[pos[Q[i].x]])-query(dfn[pos[Q[i].x]]-1);//注意双映射!
}
for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}

最新文章

  1. 洛谷P1196 银河英雄传说[带权并查集]
  2. NSPredicate 过滤功能
  3. ligureUI 刷新列求和
  4. BMP图像格式
  5. linux【报错】userdel: user xiaoming is currently used by process 4713解决
  6. C# .NET 获取枚举值的自定义属性(特性/注释/备注)信息
  7. Node.js模块 加载笔记
  8. [置顶] ProcessOn:划时代性的在线作图工具
  9. Threejs 官网 - Three.js 的图形用户界面工具(GUI Tools with Three.js)
  10. 网络安全之IP伪造
  11. Android学习笔记- ButterKnife 8.0注解使用介绍
  12. 《深入理解Bootstrap》读书笔记(一)
  13. 详解EBS接口开发之供应商导入(补充)--供应商银行账户更新
  14. Mac--Homebrew简介及安装
  15. UOJ#37. 【清华集训2014】主旋律
  16. 微信小程序中转义字符的处理
  17. adb bat 执行滑动事件
  18. elasticsearch6.7 05. Document APIs(3)GET API
  19. E:Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable)
  20. 如何在 Azure 中自定义 Windows 虚拟机

热门文章

  1. PageObject六大原则
  2. Gama Space 和 Linear Space 学习
  3. 【转】mac上安装gradle
  4. Unity代码混淆
  5. Web最最基础2
  6. 小程序开发-使用xpath解析网页html中的数据
  7. JVM 中的对象及引用
  8. Selenium-WebDriver安装
  9. nodejs解压版安装和配置(带有搭建前端项目脚手架)
  10. 用c语言处理文件