P2414 [NOI2011]阿狸的打字机

AC自动机+树状数组

优质题解 <------题目分析

先AC自动机搞出Trie图

然后根据fail指针建一只新树

把树映射(拍扁)到一个序列上,用树状数组加速优化

在新树上处理时间戳,用于树状数组维护

在原Trie树上跑dfs查询答案。

因为Trie下标从0开始,树状数组从1开始

所以所有有关的下标都要注意

attention:树状数组上限一定要+1!(就是它卡了我1天TAT)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
inline int max(int &a,int &b) {return a>b ?a:b;}
const int N=1e5+;
struct Trie{int nxt_[],nxt[],fail,end,fa;}a[N];
int n,tot,cnt,word[N],ans[N];
struct AC_automaton{ //AC自动机
char q[N];
void Trie_build(){
scanf("%s",q);
int u=,len=strlen(q),st=;
while(q[st]=='B'||q[st]=='P') ++st;
for(int i=st;i<len;++i){
if(q[i]=='B') u=a[u].fa; //删除一位
else if(q[i]=='P') word[++tot]=u,a[u].end=tot; //加入新单词
else{
int p=q[i]-'a';
if(!a[u].nxt[p]) a[u].nxt[p]=++cnt,a[cnt].fa=u;
u=a[u].nxt[p];
}
}
}
void AC_build(){
queue <int> h;
for(int i=;i<;++i) if(a[].nxt[i]) h.push(a[].nxt[i]);
while(!h.empty()){
int x=h.front(); h.pop();
for(int i=;i<;++i){
int &to=a[x].nxt[i];
if(to){
a[to].fail=a[a[x].fail].nxt[i];
h.push(to);
}else to=a[a[x].fail].nxt[i];
}
}
}
void backup(){ //对Trie树的nxt进行备份由于下面的遍历(AC自动机会改变nxt)
for(int i=;i<=cnt;++i)
for(int j=;j<;++j)
a[i].nxt_[j]=a[i].nxt[j];
}
}mo1;
struct tree_array{ //树状数组
int c[N];
inline void add(int x,int k) {for(;x<=cnt+;x+=x&-x) c[x]+=k;} //上限要+1!
inline int sum(int x){int res=; for(;x;x-=x&-x) res+=c[x]; return res;}
}mo2;
int cnt1,hd1[N],nxt1[N],ed1[N],poi1[N];
int cnt2,hd2[N],nxt2[N],ed2[N],poi2[N],id[N];
inline void add_edge1(int x,int y){ //fail树邻接表
nxt1[ed1[x]]=++cnt1; hd1[x]= hd1[x] ? hd1[x]:cnt1;
ed1[x]=cnt1; poi1[cnt1]=y;
}
inline void add_edge2(int x,int y,int _id){ //存询问邻接表
nxt2[ed2[x]]=++cnt2; hd2[x]= hd2[x] ? hd2[x]:cnt2;
ed2[x]=cnt2; poi2[cnt2]=y; id[cnt2]=_id;
}
struct new_tree{
int dfs_clock,dfn[N],low[N];
inline void dfs1(int x){ //fail树遍历
dfn[x]=++dfs_clock; //时间戳
for(int i=hd1[x];i;i=nxt1[i]) dfs1(poi1[i]);
low[x]=dfs_clock; //size[x]=low[x]-dfn[x]
}
inline void dfs2(int x){ //Trie树遍历
mo2.add(dfn[x],); //保证只有该条路径上
if(a[x].end) //该点是某个单词的结尾
{
for(int i=hd2[a[x].end];i;i=nxt2[i]){
int e=word[poi2[i]];
ans[id[i]]=mo2.sum(low[e])-mo2.sum(dfn[e]-);
}
}
for(int i=;i<;++i) if(a[x].nxt_[i]) dfs2(a[x].nxt_[i]); //沿原树遍历
mo2.add(dfn[x],-);
}
}mo3;
int main(){
mo1.Trie_build(); mo1.backup(); mo1.AC_build();
for(int i=;i<=cnt;++i) add_edge1(a[i].fail,i); //fail树连边
scanf("%d",&n); int q1,q2;
for(int i=;i<=n;++i) scanf("%d%d",&q1,&q2),add_edge2(q2,q1,i); //把询问存到邻接表上
mo3.dfs1(); mo3.dfs2();
for(int i=;i<=n;++i) printf("%d\n",ans[i]);
return ;
}

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

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

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

  2. 洛谷P2414 - [NOI2011]阿狸的打字机

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

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

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

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

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

  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. Java-查询已创建了多少个对象

    //信1603 //查询创建了多少个对象//2017.10.19public class Lei {//记录对象个数 ;//生成一个对象就自加加 public Lei() { x++; }public ...

  2. PAT甲1031 Hello World for U【字符串】

    1031 Hello World for U (20 分) Given any string of N (≥5) characters, you are asked to form the chara ...

  3. PAT-GPLT L1-039 - 古风排版 - [字符串输入输出]

    题目链接:https://www.patest.cn/contests/gplt/L1-039 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standar ...

  4. POJ 2914 - Minimum Cut - [stoer-wagner算法讲解/模板]

    首先是当年stoer和wagner两位大佬发表的关于这个算法的论文:A Simple Min-Cut Algorithm 直接上算法部分: 分割线 begin 在这整篇论文中,我们假设一个普通无向图G ...

  5. 面向切面编程--AOP(转)

    add by zhj:面向切面编程就是在不修改函数A的前提下,在函数A前后插入业务逻辑B, C, D...这其实算是功能分解,将大模块S=A+B+C+D+……分解为独立的小功能A,B,C,D……,模块 ...

  6. Android应用之——百度地图最新SDK3.0应用,实现最经常使用的标注覆盖物以及弹出窗覆盖物

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/yanglfree/article/details/33333413 一.概述 最新版的百度地图SDK ...

  7. 廖威雄: 思维导图:利用__attribute__((section()))构建初始化函数表与Linux内核init的实现

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/juS3Ve/article/details/79049404 本文具体解说了利用__attribut ...

  8. NYOJ-1073 最小值

    http://acm.nyist.net/JudgeOnline/problem.php?pid=1073 # include<stdio.h> # include<stdlib.h ...

  9. byte处理的几种方法

    /** * 字符串转16进制byte * @param * @return * @throws Exception * @author hw * @date 2018/10/19 9:47 */ pr ...

  10. 搭建本地离线yum仓库

    目录 前言 把rpm包下载到本地 配置本地yum仓库信息 生成repodata信息 检查以及使用 对本地仓库进行更新 参考资料 修改记录 环境:VMware-Workstation-12-Pro,Wi ...