其實很久以前就學了這兩個東西......但是一直懶得寫,今天補一補
基礎部分不講了,放個板子在這
void bsort()
void getsa()
k=0;
for(i=1;i<=n;height[rank[i++]]=k)
for((k?k--:k),j=sa[rank[i]-1];a[i+k]==a[j+k];k++);
}
應用嘛,還是很廣泛的
本體可以字尾排序【廢話】
求出height並且st表一下,就可以求內部lcp啦之類的,還可以套主席樹使用
多串的時候可以考慮首尾相連中間加分隔符'$'然後建sa,操作也很多
聽說還能套fft一起用?我反正沒見過
套主席樹的
套可持久化線段樹的:十二省聯考2019 字串(雖然實際上是sam題)
別的懶得放了......很多操作現想就好
candy?菊苣講的非常好,放在這裡:candy?
理解稍微有點困難......但是把有些概念當顯然成立的背下來會有很大幫助
每個節點上$right$集合是核心維護的東西,維護的是這個節點可以識別的子串的可能起點
對於每個節點$s$,都有乙個範圍$[min(s),max(s)]$
從$right$集合中的位置出發,長度在這個範圍內的子串,被sam識別以後就放在這個點!
sam也有fail樹,其實更常見叫$parent$ $tree$,相當於失配指標
對於節點$fa$和節點$s$,有性質:$max(fa)=min(s)-1$
同時,$right(fa)$是所有包含$right(s)$的集合中,最小的乙個
兩個基本用法:
往對應的兒子走,就是匹配串後面加個字元
往自己的fail走,就是匹配串前面刪個字元
板子在這裡
namespace sam
inline int newnode(int w)
void insert(int c)
} last=np;
} void sort(int n)
}}
廣義的東西,就是把很多串建成$trie$然後$bfs$插入,要記錄$last$指標下來
$right$集合裡很多資訊都可以維護,不止大小,還可以狀壓維護屬於哪個串之類的
然後,有個操作是不做最後面那個基數排序,而是每次插入完從$np$往上更新$siz$,遇到更新過的就$break$
這種時間複雜度上界好像是$o(nlogn)$,資料小(1e5)的可以用用,不要老是用
$fail$樹可以套到$lct$上,然後可以動態加元素、動態$dp$之類的
建立反串的sam,其parent樹就是原串的字尾樹!
對於乙個子串$[l,r]$,可以用在字尾樹上倍增的方式快速定位。
具體而言,我們每一次完成插入的時候記錄$last$指向的節點:那個節點就是對應的字尾在字尾樹上的位置
倍增的時候,從$l$對應的節點開始倍增,找到最淺的,$right$集合適應區間包含$r-l+1$的節點,就是這個子串在字尾樹or字尾自動機上的位置
模板 字尾陣列 字尾自動機
關於字尾自動機sam,貼乙個非常好的講解 字尾自動機學習小記 交洛谷模板可a 傳送門 洛谷 模板 字尾排序 include using namespace std const int n 1e6 5 char s n int sa n t1 n t2 n c n int n,m 555 void s...
字尾陣列與字尾自動機學習筆記
這只是個人小結,沒啥大意義。字尾陣列 其實就是通過把字串的所有字尾排序來實現一些東西。字尾排序可以用倍增 雙關鍵字來實現。然後排完之後可以求出height陣列,然後就可以用rmq求lca了。字尾自動機 各種複雜度都是線性的,非常優秀。原理 把具有相同right集合的狀態縮成乙個點,這個點內的所有狀態...
字尾自動機學習
今天終於把這週的坑填了,同樣看了很多部落格,這裡就不詳細總結了,就簡單整理一下了。應用 1 存在性查詢 給定文字t,詢問格式如下 給定字串p,問p是否是t的子串。直接按著路徑走,看是否存在即可 2 不同的子串個數 對於每乙個節點即為 len i len fa i 加和即可 3 不同子串的總長 這裡我...