1. 程式人生 > >[OI筆記]後綴自動機

[OI筆記]後綴自動機

感覺 情況 一個 ttl 後綴自動機 代碼 inline memset 課件

本來沒打算寫的,不過想想看後綴自動機的理論看了兩三天了才有點懂(我太傻了)…下周期末考的話大概要去復習一下文化課感覺回來又要忘得差不多,還是開篇blog記一下好了。

相關的資料:

cls當年的課件:2012年noi冬令營陳立傑講稿

一篇不錯的blog:http://www.cnblogs.com/meowww/p/6394960.html

因為博主比較懶(菜)所以這裏就大概記一些關鍵的東西(其實也就只復述了一遍建SAM的過程,大概在cls課件40頁左右的地方)。

用$p$表示$p=ST(T)$且$Right(p)=\{Lenght+1\}$的點(代碼裏用$last$記錄),對於字符串$T$的SAM,我們在後面加入一個新的字符$x$,新建$np=ST(Tx),val[np]=val[p]+1$,對$p$所有沒有$x$標號的祖先$v$,令$tr[v][x]=np$,也就是連向我們新加的點。

就這樣找到第一個有$x$標號的祖先$v_p$,這裏有幾種情況。如果沒有找到這樣的$v_p$直接令$suf[np]=root$(根作為$np$的父親),然後就可以結束了。否則令$q=tr[v_p][x]$,這時候如果$val[v_p]+1=val[q]$的話直接讓$suf[np]=q$然後結束,但是如果不行的話就有點麻煩了,這時候我們要再建一個點$nq:tr[nq][*]=tr[q][*]$,然後$suf[nq]=suf[q],suf[q]=suf[np]=nq$,最後對所有$tr[v][x]==q$的祖先$v$都改成$tr[v][x]=nq$。

最後當然不要忘記更新$last$。

構造大概就是這樣子啦。

inline int newNode(int x)
{
    val[++cnt]=x;return cnt;
}
inline void insert(int x)
{
    int p=last,np=newNode(val[p]+1);memset(tr[np],0,sizeof tr[np]);
    while(p&&!tr[p][x])tr[p][x]=np,p=suf[p];
    if(!p)suf[np]=1;
    else
    {
        int q=tr[p][x];
        if(val[q]==val[p]+1)suf[np]=q;
        
else { int nq=newNode(val[p]+1); memcpy(tr[nq],tr[q],sizeof tr[nq]); suf[nq]=suf[q];suf[np]=suf[q]=nq; while(p&&tr[p][x]==q)tr[p][x]=nq,p=suf[p]; } } last=np; }

寫起來還是挺短的

[OI筆記]後綴自動機