[OI筆記]後綴自動機
阿新 • • 發佈:2018-01-29
感覺 情況 一個 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筆記]後綴自動機