装载自55242字符串AC自动机专栏

fail树

定义

把所有fail指针逆向,这样就得到了一棵树
(因为每个节点的出度都为1,所以逆向后每个节点入度为1,所以得到的是一棵树)

还账…

有了这个东西,我们可以做很多事…

对于AC自动机的构造前面的文章已经讲了,而在查询的时候,有一点感觉没有说清楚:
对于x串在y串中出现,必然是在y串某个前缀的后缀与x串相同
fail指针指向与该节点表示串后缀相等的且长度最大的串(或前缀)的节点
然后,根据fail指针的原理,在查询的时候,沿着当前节点的fail指针向上查找,直到root结束。
这个过程就是在遍历当前构成的字符串的后缀中是否有其他的单词。

作用

那有了fail树这个东西,我们可以干什么呢?

考虑这样一个问题:

给定n个串,m个询问,每个询问为一对(x,y),询问串y包含几个串x;

n,m≤106,串的总长度≤106

解法1:

建好AC自动机,然后在线去查询,查询的时候每碰到一个字符就顺着fail指针往前查找到root。

解法2:

离线查询,每次查询y对应的多个x,这个只要往前找的时候统计多个就好

可是,这些解法都会TLE…所以要利用fail树

fail树就是把fail指针反转后重新建的树,这样查询(x,y),y会出现在x的子树中

先研究下查询对(x,y),如果串x出现在串y中,那么串y有几个前缀的后缀
以串x结尾,便是出现的次数,简单地说串y从某个位置顺着fail指针能到
达串x尾就增加一次.这是多对一的关系; 换个角度想,如果是一对多的话会容易解决些,从串x的末尾逆着刚刚
从串y来的fail指针能到达几个y中位置,那么就有几次. 上面那步很容易转换,但关键问题是如果逆着刚刚从串y来的指针走呢?
逆着fail指针重新建树!
这就是fail树了.当我们构建好了fail树之后,要做的就是查询x的子树中有几个节点属于串y.
求出fail树的dfs序,令l[x]和r[x]分别为x遍历开始和结束的位置. 接着我们进行区间查询,令表示查询l[x]和r[x]之间有几个属于y的结点. 把串y在ac自动机上的结点对应的下标全赋值成1,问题就转变为l[x]和r[x]里有几个1了,
这时使用树状数组来计算区间和.
我们采用离线查询,把所有有y的查询存起来,当遇到y的末节点的时候拿出来统一处理.
我们顺着建AC自动机时的路线再遍历一遍AC自动机,遇到普通字母对应下标的值赋成1,
遇到B减1,遇到P查询(NOI 2011 阿狸的打字机)

题目

  1. CF 163 E
  2. BZOJ 3172: [Tjoi2013]单词
  3. BZOJ 2434 [Noi2011]阿狸的打字机

TRIE图

建议先看一下Trie图的构建、活用与改进

看不懂很正常….

定(xian)义(che)

Trie图实际上一个确定性有限状态自动机,比AC自动机增加了确定性这个属性.

对于AC自动机来说,当碰到一个不匹配的节点后可能要进行好几次回溯才能进行下一次匹配;但是对于trie图来说,可以每一步进行一次匹配,每碰到一个输入字符都有一个确定的状态节点。

trie图的后缀节点跟ac自动机的后缀指针基本一致,区别在于trie图的根添加了了所有字符集的边;另外trie图还会为每个节点补上所有字符集中的字符的边,而这个补边的过程实际上也是一个求节点的后缀节点的过程.不过这些节点都是虚的,我们不把它们加到图中,而是找到它们的等价节点即它们的后缀节点, 从而让这些边指向后缀节点就可以了.

实现

Trie图主要利用两个概念实现这种目的。 后缀节点 和 补边 操作.

相关操作

  1. 后缀节点,也就是每个节点的路径字符串去掉第一个字符后的字符串对应的 节点.计算这个节点的方法,是通过它父亲节点的后缀节点,很明显它父亲的 后缀节点与它的后缀节点的区别就是还少一个尾字符,设为c,所以节点的父 节点的指针的c孩子就是该节点的后缀节点.但是因为有时候它父亲不一定有c孩子,所以还得找一个与父亲的c孩子等价的节点.于是就碰到一个寻找等价 节点的问题。
  2. 而Trie图还有一个补边的操作,不存在的那个字符对应的边指向的节点实际 上可以看成一个虚节点,我们要找一个现有的并且与它等价的节点,将这个边 指向它.这样也实际上是要寻找等价节点。

实现相关

我们看怎么找到一个节点的等价节点,我们所谓的等价是指它们的危险性一致。那我们再看一个节点是危险节点的充要条件是:它的路径字符串本身就是一个危险单词,或者它的路径字符串的后缀对应的节点是一个危险节点.因此我们可以看到,如果这个节点对应的路径字符串本身不是一个危险单词.那它就与它的后缀节点是等价的.所以我们补边的时候,实际指向的是节点的后缀节点就可以了.

trie图实际上对trie树进行了改进,添加了额外的信息。

使得可以利用它方便的解决多模式串的匹配问题.跟kmp的思想一样,trie图也是希望利用现在已经匹配的信息,对未来的匹配提出指导.提出了一些新的概念。定义trie树上,从根到某个节点的路径上所有边上的字符连起来形成的字符串称为这个节点的路径字符串.如果某个节点的路径字符串以一个危险字符串结尾,那么这个节点就是危险节点:也就是说如果到达这个点代表是匹配的状态;否则就是安全节点。 那么如何判断某个节点是否危险呢?

根节点显然是安全节点。一个节点是危险节点的充要条件是:它的路径字符串本身就是一个危险单词,或者它的路径字符串的后缀(这里特指一个字符串去掉第一个字符后剩余的部分)对应的节点(一个字符串对应的节点,是指从trie图中的根节点开始,依次沿某个字符指定的边到达的节点)是一个危险节点。

那么如何求每一个节点的后缀节点呢?这里就可以里利用以前的计算信息,得到了。具体来说就是利用父亲节点的后缀节点,我们只要记住当前节点的最后一个字符设为C,那么父亲节点的后缀节点的C分支节点就是要求的后缀节点了。首先我们限定,根节点的后缀节点是根本身,第一层节点的后缀节点是根节点。这样我们可以逐层求出所有节点的后缀节点。但是这个过程中,可能出现一个问题:父亲节点的后缀节点可能没有c分支。这时候该怎么办呢?

如下图所示如果设当前节点的父亲节点的后缀节点为w,我们假设w具有c孩子为,我们可以看到对于w的整个c子树来说,因为根本不存在通向它们的边c,它们也就不可能是不良字符串,这样这些节点的危险性也就等价与它们的后缀节点的危险性了,而它们的后缀节点,实际上就是w的后缀节点的c孩子,如此回溯下去,最后就能找到。

总结

Trie图所起到的作用就是建立一个确定性有限自动机DFA,图中的每点都是一个状态,状态之间的转换用有向边来表示。Trie图是在Tire的基础上补边过来的,其实他应该算是AC自动机的衍生,AC自动机只保存其后缀节点,在使用时再利用后缀节点进行跳转,并一直迭代到找到相应的状态转移为止,这个应该算是KMP的思想。

过程:

1. 构建Trie,并保证根节点一定有|∑|个儿子。
2. 层次遍历Trie,计算后缀节点,节点标记,没有|∑|个儿子的对其进行补边。

后缀节点的计算:

1. 根结点的后缀节点是它本身。
2. 处于Trie树第二层的节点的后缀结点也是根结点。
3. 其余节点的后缀节点,是其父节点的后缀节点中有相应状态转移的节点(这里类似AC自动机的迭代过程)。

节点标记:

1.本身就有标记。
2.其后缀节点有标记。

补边:

用其后缀节点相应的状态转移来填补当前节点的空白。
最后Trie图中任意一个节点均有相应的状态转移,我们就用这个状态转移做动态规划。

AC自动机相关Fail树和Trie图相关基础知识的更多相关文章

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

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

  2. AC自动机学习笔记-2(Trie图&&last优化)

    我是连月更都做不到的蒟蒻博主QwQ 考虑到我太菜了,考完noip就要退役了,所以我决定还是把博客的倒数第二篇博客给写了,也算是填了一个坑吧.(最后一篇?当然是悲怆のnoip退役记啦QAQ) 所以我们今 ...

  3. 【BZOJ2434-[Noi2011]】阿狸的打字机(AC自动机(fail树)+离线+树状数组)

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

  4. BZOJ3881 Coci2015Divljak(AC自动机+树上差分+树状数组)

    建出AC自动机及其fail树,每次给新加入的串在AC自动机上经过的点染色,问题即转化为子树颜色数.显然可以用dfs序转成序列问题树状数组套权值线段树解决,显然过不掉.事实上直接树上差分,按dfs序排序 ...

  5. BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)

    题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...

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

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

  7. CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)

    What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...

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

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

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

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

随机推荐

  1. 常见的爬虫分析库(4)-爬虫之PyQuery

    PyQuery 是 Python 仿照 jQuery 的严格实现.语法与 jQuery 几乎完全相同. 官方文档:http://pyquery.readthedocs.io/ 安装 1 pip ins ...

  2. vs2017初学c++环境配置及使用教程

    https://blog.csdn.net/jmpan_sjtu/article/details/79053169 https://blog.csdn.net/luoyu510183/article/ ...

  3. webpack学习笔记--配置entry

     Entry entry 是配置模块的入口,可抽象成输入,Webpack 执行构建的第一步将从入口开始搜寻及递归解析出所有入口依赖的模块. entry  配置是必填的,若不填则将导致 Webpack ...

  4. 盘点那些Vs中常用到的Tab快捷编码

    1.快速声明for循环:for+Tab 2.快速声明Foreach遍历:foreach+Tab 3.快速定义属性:prop+Tab 4.

  5. Redis-Sentinel 哨兵

    为什么需要哨兵? 一旦主节点宕机,那么需要人为修改所有应用方的主节点地址(改为新的master地址),还需要命令所有从节点复制新的主节点 那么这个问题,redis-sentinel就可以解决了 什么是 ...

  6. .net core2.1 - ef core数据库迁移,初始化种子数据

    起因:早上偶然看见一篇文章说是ef core(2.x)使用种子数据,主表子表迁移时候,正常情况下说是无法迁移成功,索性就试试,结果是和ef6的一样,没感觉有什么大的区别.一切OK,见下面内容. 1.首 ...

  7. spark操作Kudu之写 - 使用DataFrame API

    在通过DataFrame API编写时,目前只支持一种模式“append”.尚未实现的“覆盖”模式 import org.apache.kudu.spark.kudu._ import org.apa ...

  8. 在 Wiki 标记中添加无序列表

    项目:在 Wiki 标记中添加无序列表在编辑一篇维基百科的文章时,你可以创建一个无序列表,即让每个列表项占据一行,并在前面放置一个星号.但是假设你有一个非常大的列表,希望添加前面的星号.你可以在每一行 ...

  9. fastAdmin进阶

    基本知识流程一栏链接 bootstrapTable fastadmin系统配置(符内置规则): fastadmin默认的controller已实现的方法 一张图解析fastadmin的表格: fast ...

  10. oracle中

    select tmp_tb.*, ROWNUM row_id from (SELECT MX.*                                          --这里不能直接用* ...