AC自动机相关Fail树和Trie图相关基础知识
装载自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 阿狸的打字机)
题目
- CF 163 E
- BZOJ 3172: [Tjoi2013]单词
- BZOJ 2434 [Noi2011]阿狸的打字机
TRIE图
建议先看一下Trie图的构建、活用与改进
看不懂很正常….
定(xian)义(che)
Trie图实际上一个确定性有限状态自动机,比AC自动机增加了确定性这个属性.
对于AC自动机来说,当碰到一个不匹配的节点后可能要进行好几次回溯才能进行下一次匹配;但是对于trie图来说,可以每一步进行一次匹配,每碰到一个输入字符都有一个确定的状态节点。
trie图的后缀节点跟ac自动机的后缀指针基本一致,区别在于trie图的根添加了了所有字符集的边;另外trie图还会为每个节点补上所有字符集中的字符的边,而这个补边的过程实际上也是一个求节点的后缀节点的过程.不过这些节点都是虚的,我们不把它们加到图中,而是找到它们的等价节点即它们的后缀节点, 从而让这些边指向后缀节点就可以了.
实现
Trie图主要利用两个概念实现这种目的。 后缀节点 和 补边 操作.
相关操作
- 后缀节点,也就是每个节点的路径字符串去掉第一个字符后的字符串对应的 节点.计算这个节点的方法,是通过它父亲节点的后缀节点,很明显它父亲的 后缀节点与它的后缀节点的区别就是还少一个尾字符,设为c,所以节点的父 节点的指针的c孩子就是该节点的后缀节点.但是因为有时候它父亲不一定有c孩子,所以还得找一个与父亲的c孩子等价的节点.于是就碰到一个寻找等价 节点的问题。
- 而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图相关基础知识的更多相关文章
- [NOI2011]阿狸的打字机——AC自动机之fail树的利用
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- AC自动机学习笔记-2(Trie图&&last优化)
我是连月更都做不到的蒟蒻博主QwQ 考虑到我太菜了,考完noip就要退役了,所以我决定还是把博客的倒数第二篇博客给写了,也算是填了一个坑吧.(最后一篇?当然是悲怆のnoip退役记啦QAQ) 所以我们今 ...
- 【BZOJ2434-[Noi2011]】阿狸的打字机(AC自动机(fail树)+离线+树状数组)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- BZOJ3881 Coci2015Divljak(AC自动机+树上差分+树状数组)
建出AC自动机及其fail树,每次给新加入的串在AC自动机上经过的点染色,问题即转化为子树颜色数.显然可以用dfs序转成序列问题树状数组套权值线段树解决,显然过不掉.事实上直接树上差分,按dfs序排序 ...
- BZOJ 2434 阿狸的打字机(ac自动机+dfs序+树状数组)
题意 给你一些串,还有一些询问 问你第x个串在第y个串中出现了多少次 思路 对这些串建ac自动机 根据fail树的性质:若x节点是trie中root到t任意一个节点的fail树的祖先,那么x一定是y的 ...
- BZOJ2434: [NOI2011]阿狸的打字机(AC自动机+dfs序+树状数组)
[NOI2011]阿狸的打字机 题目链接:https://www.luogu.org/problemnew/show/P2414 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. ...
- CF547E Milk and Friends(AC自动机的fail指针上建主席树 或 广义后缀自动机的parent线段树合并)
What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercas ...
- BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...
- BZOJ2434[Noi2011]阿狸的打字机——AC自动机+dfs序+树状数组
题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...
随机推荐
- 刚发了两个关于极光推送的网上Demo,再次自己结合官网总结一下,以便加深印象
简单源码如下: //Map<String, String> parm是我自己传过来的参数,同学们可以自定义参数public static void jpushAndroid(Map< ...
- Windows文件系统
微软在Dos/Windows系列操作系统中共使用了6种不同的文件系统(包括即将在windows的下一个版本中使用的Winfs).它们分别是:FAt12.FAT16.FAT32.NTFS.NTFS5.0 ...
- python 内置数据类型之字符串
1.3 字符串 字符串本身就是一个有序(从左至右)的字符的集合.是序列这种类型的一种,后面还要学习列表与元组. 在这一节中,需要了解字符串的定义,特殊字符,转义与抑制转义:字符串基本操作.格式化等. ...
- MySql-8.0.12 安装教程
MySql-8.0.12 安装教程随笔https://www.cnblogs.com/CrazyDemo/p/9409995.html MySQL 安装https://m.runoob.com/mys ...
- 将现有项目添加到TFS中
假设在Projects文件夹中有一个名为WpfApplication1的项目需要添加到TFS. 我们可以这样做: 1.打开视图->团队资源管理器,点击管理连接,在弹出的窗口中选择服务器和团队项目 ...
- 学习笔记: 反射应用、原理,完成扩展,emit动态代码
using Ruanmou.DB.Interface; using Ruanmou.DB.MySql; using Ruanmou.DB.SqlServer; using Ruanmou.Model; ...
- CentOS6—HAProxy安装与配置
概述 Haproxy下载地址:http://pkgs.fedoraproject.org/repo/pkgs/haproxy/ 关闭SElinux.配置防火墙 1.vi /etc/selinux/co ...
- python2 python3 转换,兼容
0. 1.参考 https://docs.python.org/3/library/urllib.html urllib is a package that collects several modu ...
- 如何在grails2.3.x中的fork模式下进行调试?-【grails】
grails2.3.x中默认情况下运行模式被设置成了fork模式,在这种模式下,大家会发现设置了断点后无法进行中断.这是由于fork模式造成的,因为在fork模式下,JVM新起了一个进程,这样调试器就 ...
- python__int 部分内部功能介绍
查看创建的对象的类型: age=18 print(type(age)) 结果: <class 'int'> x.bit_length():返回二进制的位数 Python中进制的转换: Py ...