题意

给定n个模式串,有m个询问,每次询问第X个模式串在第Y个模中出现了多少次

解题思路

以fail树相反的方向建一棵树T,问题转化为X的子树中有多少个y的终止节点。跑出T的dfs序,X的子树就可以表示为一段区间,然后对trie跑一遍dfs,每进入一个点就把dfs序列上对应的位置+1,离开一个点就把dfs序列上对应的位置-1,遍历到y的终止节点就计算所有Y=y的询问的结果,计算方法就是区间求和,用树状数组或线段树可以轻易地维护。

AC代码

#include<bits/stdc++.h>
using namespace std; typedef long long ll;
const int maxn=2e5+5;
char s[maxn];
struct Query{
int x,y,id,ans;
bool operator<(const Query& b)const{return y<b.y;}
}q[maxn];
int ql[maxn],qr[maxn],pos[maxn]; //BIT
int c[maxn];
inline int lowbit(int x){return x&(-x);}
void add(int x,int d){for(;x<maxn-5;x+=lowbit(x))c[x]+=d;}
int getsum(int x){int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
int getsum(int l,int r){return getsum(r)-getsum(l-1);} //AC_Automaton
//root=0,range[1,tot]
const static int SIZE=26;
int tr[maxn][SIZE],fail[maxn],tot;
int fa[maxn],val[maxn],ch[maxn][SIZE];
void insert(){
int p=0,cnt=0;
for(int i=0;s[i];i++){
if(s[i]=='P'){pos[++cnt]=p;val[p]=cnt;}
else if(s[i]=='B')p=fa[p];
else{
if(!tr[p][s[i]-'a'])tr[p][s[i]-'a']=++tot;
fa[tr[p][s[i]-'a']]=p;
p=tr[p][s[i]-'a'];
}
}
for(int i=0;i<=tot;i++)for(int j=0;j<26;j++)ch[i][j]=tr[i][j];
}
void getfail(){
queue<int>q;
for(int i=0;i<SIZE;i++)if(tr[0][i])fail[tr[0][i]]=0,q.push(tr[0][i]);
while(!q.empty()){
int p=q.front();q.pop();
for(int i=0;i<SIZE;i++){
if(tr[p][i]){
fail[tr[p][i]]=tr[fail[p]][i],q.push(tr[p][i]);
}
else tr[p][i]=tr[fail[p]][i];
}
}
} //inv fail tree
struct Edge{
int v,nxt;
}e[maxn];
int fi[maxn],se[maxn],sz;
int head[maxn],num;
void init_graph(){
memset(head,0,sizeof(head));
num=1;
}
void addedge(int u,int v){e[num].v=v;e[num].nxt=head[u];head[u]=num++;}
void dfs_fail(int p){
fi[p]=++sz;
for(int i=head[p];i;i=e[i].nxt)dfs_fail(e[i].v);
se[p]=sz;
} //get ans
int Ans[maxn];
void dfs_trie(int p){
add(fi[p],1);
if(val[p]){
for(int i=ql[val[p]];i<=qr[val[p]];i++)
q[i].ans=getsum(fi[pos[q[i].x]],se[pos[q[i].x]]);
}
for(int i=0;i<26;i++)if(ch[p][i])dfs_trie(ch[p][i]);
add(fi[p],-1);
} int main()
{
//#ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
//#endif
scanf("%s",s);
insert(); getfail();
init_graph();
for(int i=1;i<=tot;i++)addedge(fail[i],i);
sz=0;dfs_fail(0);//建inv fail tree,跑出dfs序 int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&q[i].x,&q[i].y);
q[i].id=i;q[i].ans=0;
}
sort(q+1,q+1+n);
for(int i=1,t=1;i<=n;i++){
ql[q[i].y]=i;
while(q[t+1].y==q[i].y)t++;
qr[q[i].y]=t;i=t;
}
dfs_trie(0);//遍历trie,跑出答案 for(int i=1;i<=n;i++)Ans[q[i].id]=q[i].ans;
for(int i=1;i<=n;i++)printf("%d\n",Ans[i]);
return 0;
}

P2414 [NOI2011]阿狸的打字机 AC自动机的更多相关文章

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

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

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

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

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

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

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

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

  5. [NOI2011]阿狸的打字机 --- AC自动机 + 树状数组

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

  6. bzoj 2434 [Noi2011]阿狸的打字机 AC自动机

    [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4001  Solved: 2198[Submit][Status][D ...

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

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

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

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

  9. [NOI2011]阿狸的打字机——AC自动机之fail树的利用

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

随机推荐

  1. 十分钟搭建自己的私有NuGet服务器-BaGet

    目录 前言 开始 搭建BaGet 上传程序包 在vs中使用 其他 最后 前言 NuGet是用于微软.NET(包括 .NET Core)开发平台的软件包管理器.NuGet能够令你在项目中添加.移除和更新 ...

  2. SQL语句:在两个数据库间复制表结构和数据数据库

    一.如果两个数据库在同一台服务器上 1.复制表结构和数据:SELECT * INTO DatabaseB.dbo.TableB FROM DatabaseA.dbo.TableA 2.仅仅复制表结构: ...

  3. 我是键盘侠-键盘流神器Vimium

    黑客的浏览器. Vimium本着Vim的精神为导航和控制提供键盘快捷键. 注意:谷歌不允许 Vimium在 Chrome Web Store页面和 新选项卡页面上运行.所以按键无效不要惊讶 Vimiu ...

  4. Go:内存管理与内存清理

    Illustration created for "A Journey With Go", made from the original Go Gopher, created by ...

  5. HTTP POST 请求的两种编码格式:application/x-www-form-urlencoded 和 multipart/form-data

    在常见业务开发中,POST 请求常常在这些地方使用:前端表单提交时.调用接口代码时和使用 Postman 测试接口时.我们下面来一一了解: 一.前端表单提交时 application/x-www-fo ...

  6. JavaScript calss语法糖

    JavaScript calss语法糖 基础知识 严格意义上来讲,在Js中是没有类这一概念的. 我们可以运用前面章节提到的构造函数来模拟出类这一概念,并且可以通过原型对象的继承来完美的实现实例对象方法 ...

  7. 使用Python语言通过PyQt5和socket实现UDP服务器

    前言 最近做了一个小软件,记录一下相关内容. 已有条件 现在已有一个硬件设备作为客户端(暂称其为"电路"). 基于SIM卡,电路可以通过UDP协议传输数据(程序已经内置在电路中), ...

  8. Kinect+unity 实现体感格斗闯关小游戏

    文章目录 项目地址 1 项目概况 1.1 项目简介 1.2 项目目的 1.3 主要技术 2 设计 2.1 基本概念 2.2 框架 2.3 算法 2.4 模型 2.5 调查问卷 3 实现 3.1 技术难 ...

  9. Android SharedPreferences存储详解

    什么是SharedPreferences存储 一种轻量级的数据保存方式 类似于我们常用的ini文件,用来保存应用程序的一些属性设置.较简单的参数设置. 保存现场:保存用户所作的修改或者自定义参数设定, ...

  10. C#图解教程(第四版)—02—类的基本概念

    类  是一种能 存储数据  并且  执行代码  的数据结构,他包含数据成员和函数成员 .成员可以是9种可能的成员类型的任意组合 字段 属性 方法 常量 构造函数 析构函数 运算符 索引器 事件 1 字 ...