广义后缀自动机
前置知识:./后缀自动机.md
广义后缀自动机 (General Suffix Automaton) 是将后缀自动机整合到字典树中来解决对于多个字符串的子串问题
常见的伪广义后缀自动机
- 通过用特殊符号将多个串直接连接后,再建立 SAM
- 对每个串,重复在同一个 SAM 上进行建立,每次建立前,将 lst指针置零
一般情况下,这两种方法的时间复杂度与广义后缀自动机的最坏时间复杂度相同,但如果题目给的是 Trie 的话效率差距就很大了。
在线构建广义后缀自动机
在线构建广义后缀自动机的复杂度优于离线构建,且实现较好理解,其实现依赖于对 insert() 的修改。
和上面一样,lst 不记录在 exSAM 中而是由 insert() 返回,每次在上次的基础上新增节点。
对每个字符串,我们都从 lst = 0 开始构建 exSAM,我们对 \(sam_lst.son_c\) 是否已存在分类讨论:
- 如果还不存在,那么按照正常的 SAM 执行即可。
- 否则,我们令 \(p \leftarrow lst, np \leftarrow sam_lst.son_c\) 并检查是否有 \(len_{np} = len_{p} + 1\):
- 如果是,那么 \(np\) 就是我们想新建的点,直接返回即可。
- 否则我们要做类似 SAM 中分裂的事情,我们令 \(nq \leftarrow clone(np)\),令 \(len_{nq} \leftarrow len_{np} + 1\),并一样的跳后缀链接去一路修改所有到 \(np\) 的转移,不用的是,这里的 \(nq\) 才是真正代表我们新来的字符的节点,因此应当返回 \(nq\)。
 
int tot = -1,lst;
struct node
{
    int son[26],fa,len;
}sam[N];
void newnode(int len)
{
    sam[++tot].len = len;
    sam[tot].fa = -1;
}
void insert(int c)
{
    int p = lst,np = sam[p].son[c];
    if(np)
    {
        if(sam[np].len == sam[p].len + 1) lst = np;
        else
        {
            newnode(sam[p].len + 1);
            int nq = tot;
            memcpy(sam[nq].son,sam[np].son,sizeof sam[nq].son);
            sam[nq].fa = sam[np].fa;
            sam[np].fa = nq;
            while(p != -1 && sam[p].son[c] == np) sam[p].son[c] = nq,p = sam[p].fa;
            lst = nq;
        }
    }
    else
    {
        newnode(sam[p].len + 1);
        np = tot;
        while(p != -1 && !sam[p].son[c])
        {
            sam[p].son[c] = np;
            p = sam[p].fa;
        }
        if(p == -1) sam[np].fa = 0;
        else
        {
            int q = sam[p].son[c];
            if(sam[q].len == sam[p].len + 1) sam[np].fa = q;
            else
            {
                newnode(sam[p].len + 1);
                int nq = tot;
                memcpy(sam[nq].son,sam[q].son,sizeof sam[nq].son);
                sam[nq].fa = sam[q].fa;
                sam[np].fa = sam[q].fa = nq;
                while(p != -1 && sam[p].son[c] == q)
                {
                    sam[p].son[c] = nq;
                    p = sam[p].fa;
                }
            }
        }
        lst = np;
    }
}
signed main()
{
    newnode(0);
    int n = rd();
    while(n--)
    {
        string s;
        cin >> s;
        lst = 0;
        for(char c : s) insert(c - 'a');
    }
    //...
    return 0;
}
 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号