后缀自动机详细理解

struct SAM {
    int ch[M][26], par[M], ml[M];
    int siz, rt, last;
    inline void set() {
        siz = rt = last = 1;
        memset(ch, 0, sizeof ch);
        memset(par, 0, sizeof par);
        memset(ml, 0, sizeof ml);
    }
    inline void extend(int c) {
        int p = last, cur = ++siz;                // 新建节点 cur
        ml[cur] = ml[p] + 1;                    // 新建节点的 maxlen 是上一个节点的 maxlen + 1
        for (; p && !ch[p][c]; p = par[p]) ch[p][c] = cur;
                                                // 沿着 suffix-link 找到第一个非空的 state ,沿途设置转移 trans(x, c) = cur
        if(!p) par[cur] = rt;                    // 如果没有被占用的 state,那么 suffix-link 连到 empty-state,也就是 root
        else {
            int q = ch[p][c];                    // 原来连到的点 q
                                                // 由于 maxlen[p] + 1 = minlen[q], 所以不可能存在 maxlen[p] + 1 > maxlen[q]
            if(ml[q] == ml[p] + 1) par[cur] = q;
                                                // 如果恰好等于 maxlen[p] + 1,那么就什么也不用设置了,suffix-link 连到 q 即可(因为已经包含之后所有 suffix 了)
            else {                                // maxlen[p] + 1 < maxlen[q]
                int sq = ++siz;                    // 新建辅助节点 sq
                par[sq] = par[q];
                for (int i=0; i<26; ++i) ch[sq][i] = ch[q][i];
                                                // 复制 q 的信息到 sq
                ml[sq] = ml[p] + 1;                // 分裂成两部分,前半部分sq,后半部分q
                par[q] = par[cur] = sq;            // 把 q 和 cur 的 suffix-link 都设为 sq
                for (; p && ch[p][c] == q; p = par[p]) ch[p][c] = sq;
                                                // 把原来到 q 的 transition 改为到 sq
            }
        }
        last = cur;
    }
}S;

代码实现参考:http://www.cnblogs.com/candy99/p/6374177.html

SAM教程推荐:https://huntzhan.org/suffix-automaton-tutorial/

时间: 2024-12-25 04:21:56

后缀自动机详细理解的相关文章

bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对广义后缀自动机的一些理解

先说一下对后缀自动机的理解,主要是对构造过程的理解. 构造中,我们已经得到了前L个字符的后缀自动机,现在我们要得到L+1个字符的后缀自动机,什么需要改变呢? 首先,子串$[0,L+1)$对应的状态不存在,应当建立一个状态来表示这个串,显然,这个状态(np)的right集合是{L+1},max=L+1. 现在新建立了一个状态,我们还有两件事要干:找出能转移到这个状态的状态,建立链接:确定这个状态的min,即找到它在parent树上的父亲. 能转移到$np$的状态显然都是right集合包含L的状态,

POJ 1509 Glass Beads 后缀自动机

题目大意:给出一个环形的字符串,问从哪里开始是的这个字符串的字典序最小. 思路:最小表示法和后缀自动机的裸题,不过我是为了学后缀自动机才写的这个题,就没有去学最小表示法. 做法很简单,先建立一个后缀自动机,然后从根开始沿tranc指针从a->z走len次到达的点就是字典序最小的字符串的结尾点,求起始点只要减一下长度再+1即可. 对于后缀自动机的理解:http://wyfcyx.is-programmer.com/posts/76107.html CODE: #include <cstdio&g

后缀自动机的直观理解

后缀自动机(SAM) 搜了网上,多介绍应用,[3]算是一个比严格的定义性描述,并给出了证明.但是这个证明我并未看懂,下面综合一些资料给一些个人的直观但不失严谨的理解. 给定一个串A的后缀自动机是一个有限状态自动机(DFA),它能够且仅能够接受A的后缀,并且我们要求它的状态数最少. 设n=|A|, 状态数:st=[n+1,2n-1], 边数:eg=[n,3n-4].构造:空间复杂度:26*st, 时间复杂度O(3n).查询:O(|q|); 可以看出,我们有可能把26*st优化到3*st的. 先上图

后缀自动机的一点点理解

后缀自动机的一点点理解 前言 最近心血来潮,想学学SAM,于是花了一晚上+一上午 勉强打了出来(但是还是不理解) 虽说张口就讲我做不到 但是一些其他的东西还是有所感触的 索性,乱口胡点东西,谢谢关于SAM的一些简单的理解 资料 丽洁姐WC PPT hihocoder上的后缀自动机 一些概念 这些概念都不读懂,接下来真的是步履维艰 本来我们要的是一个能够处理所有后缀的数据结构 但是我们发现,如果对于每一个后缀都要插入进Trie树 空间复杂度完全背不动(\(O(n^2)\)级别) 于是,后缀自动机出

浅谈对后缀自动机的一点理解

后缀自动机入门详解及模板 后缀自动机 自动机 要想了解后缀自动机,首先得了解自动机. 例如AC自动机,AC自动机可以识别一个字符串为其所匹配的前缀. 而我们今天所介绍的后缀自动机则是识别一个字符串为自动机串的子串. 在接下来的描述中为了方便,简称\(SAM\). 暴力实现 我们知道字典树有着优良的时空复杂度,并且可以支持识别一个字符串的前缀. 如果我们将串中的所有后缀插入进字典树,那么就可以实现这个自动机的功能. 不过,由于忽视了后缀的这个性质,总点数高达\(O(n^2)\). 即使如此,字典树

关于后缀自动机的一些理解

咕咕咕了好久的东西,以前只是粗糙的背个板子之类的,并未对parent树有什么深刻的理解 clj姐姐tql,这么神仙的东西是怎么想出来的啊 个人认为有以下几点是难以理解的: 一.right集合的定义: right集合就是指某一子串在原串当中出现的所有的位置的集合,也在某位大佬博客中叫做endpos集合: 二.right集合(endpos集合)相同的我们称为endpos等价类(重点理解) 三.对于任意两个endpos集合中,那么必然为其中一个为另一个的子串,或者两者绝无交集 四.endpos的等价类

[转]后缀自动机

原文地址:http://blog.sina.com.cn/s/blog_8fcd775901019mi4.html 感觉自己看这个终于觉得能看懂了!也能感受到后缀自动机究竟是一种怎样进行的数据结构了... 笔者自己的话会用楷体表示出来...[说不定能帮助大家理解,但是可能也破坏了大家的自主理解力?所以...看不懂的话再来看好咯...] 常用的字符串处理工具: 1.       整词索引:排序+二分:Hash表.可以解决整词匹配,但不支持前缀搜索:Hash表在模式串定长的情况下可以用RK解决多模式

hdu 4622 Reincarnation(后缀数组|后缀自动机|KMP)

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 2138    Accepted Submission(s): 732 Problem Description Now you are back,and have a task to do: Given you a string s consist of lo

后缀自动机小结 (spoj 8222)

后缀自动机理解关键点: 1. 根到任意一个结点都可以形成S的一个子串,并且S的所有子串都可以通过这种方式形成; 2. 到达该节点是所有路径就是一个right集合,一个拥有相同后缀的right集合; 3. 设某子串为str,这后缀自动机读入str后能到达的状态为right(str),即str在S中出现的位置的集合; 4. 假设node[b].fa = a,则状态a可以代替状态b进行识别. 附图: 更详细的资料: http://wenku.baidu.com/view/90f22eec551810a