先學習的是字尾樹向的字尾自動機qaq
介紹字尾樹的定義:
把所有字尾插到trie裡
然而實際上是插到trie裡之後再壓縮掉一些邊,這樣就是字尾樹了。
但我們發現如果乙個乙個找的話複雜度是o(
n2)
我們考慮倒著建立字尾樹,即:
串s = a+
s′那麼我們先建立s′
的字尾樹,然後建立a+
s′的字尾樹。
這樣的話我們每次只會在字尾樹裡面加入乙個新的字尾。
然後我們引入一些定義:
首先,對於字尾樹中的每個節點x,我們到根的那條路徑一定代表了乙個字串s。 de
px表示當前節點x的深度。 tr
ans(
ch) 擁有ch
+s這個字串作為字首的深度最淺的節點。
更簡易的,我們可以定義tr
ans(
ch) 表示當前節點
這樣的話我們可以考慮怎麼建立一棵字尾樹:
演算法流程:
如果我們已經建好了
s 的字尾樹,我們要建立x+
s的字尾樹。
我們新加入的這個串的節點規定為
p 。
考慮字尾樹中表示字串
s的節點是
u ,那麼我們知道tr
ans(
x)在u
處必然為空。
我們考慮往上跳到
u的某個祖先
w ,使得:tr
ans(
x)!=
null
這個也就意味著什麼呢? 設w
所代表的字串為s′
,那麼我們知道x+
s′會到達
w 的tr
ans(
x)處。 假如
w 的tr
ans(
x)是q
。我們找到了
q,並且找到了v=
parq
。 現在問題考慮兩點: 1.s
q == 1+
sw那麼我們就可以直接把x+
s 的剩餘部分掛到下面。 2.s
q > 1+
sw(即sq
的某乙個字首是x+
sw)
那麼我們就要:
①找到1+s
w 在v−
>
q 之間的那個位置。
②把邊拆成v−
>r,
r−>p,
r−>q
結束。字尾樹的構造偽**:
n = strlen(s);
now = root = new_node,len = 0;
for i:= n downto 1:
x = s[i];
w = now,now = new_node;
len = n - i + 1;
while(w != null && w -> trans[x] == null):
w -> trans[x] = now;
w = w -> father;
if w == null:
then
now -> fa = root;
else:
q = w -> trans[x];
if q -> len == w -> len + 1:
then
now -> fa = q;
else:
r = new_node;
r -> len = w -> len + 1;
r -> q,r -> now;
q -> fa = r,now -> fa = r;
while(w != null && w -> trans[x] == q):
w -> trans[x] = r;
w = w -> fa;
感覺上大致意思應該是對的,到時候補題+更改**。
佔字尾自動機的坑qaq
字尾自動機轉字尾樹模板
終於找到教程了,現在來寫一發 題目 jzoj4072 bzoj3998 弦論 第一問 其實非常好寫,連空間都不需要多開一倍,只需要sa陣列rank陣列和height陣列就好了,dfs一次可以求出 include include include include define n 1000010 usi...
字尾自動機
基礎知識 step i 表示的是字串i在原字串中的位置。pareint i 表示root到parent i 的子串是root到i的最長字尾。字尾自動機遍歷可以得到原字串的所有子串。特殊技巧 一 字尾自動機的不同子串數有兩種求法 1.ans step i step parent i 1 i cnt 2...
字尾自動機
常用於處理字串問題,可以高效解決許多字串問題。有點像將乙個字串的所有字尾都建在乙個ac自動機上,但不同的是字尾自動機的節點數最多為2 n,因為它只記錄需要記錄的點,一些沒有記錄東西的點可以視為與下面有價值的節點並在一起,這樣大大降低了時間複雜度和空間複雜度。對於每乙個節點記錄它的後面加上每個字元後字...