迴文樹

lrx139發表於2024-03-13

例題 HDU-5421 翻譯

如果字串是靜態的,則可以使用 Manacher 演算法。但本題的字串可以動態在首位新增字元,無法使用 Manacher。

本題可以使用迴文樹(迴文自動機)演算法。該演算法的時間複雜度為 \(\mathcal{O}(N)\),但空間複雜度較差,因為其本質上是字典樹。

1 迴文樹的關鍵技術

迴文樹的關鍵技術為奇偶字典樹 \(+\) 字尾鏈跳躍。下面給出思維過程。

  1. 字尾鏈跳躍

比如在 abcb 後面插入 a,則新插入的 a 與第一個 a 之間的所有字元構成了一個迴文串。

那如果是插入了 c,其不能與開頭的 a 構成迴文串,該怎麼辦呢?

可以發現上面插入 a 時,本質上就是嘗試在原串的字尾迴文串 bcb 左右各擴充套件一個字元。如果新插入的字元與上一個迴文串的前一個字母相同,那這個迴文串就可以向左右各擴充套件一個字元了。但如果不同,那我們就應該找下一個短一點的迴文串進行嘗試,如上面的例子中嘗試擴充套件 bcb 失敗,接下來以最後一個 b 結尾的最長迴文串為 b 本身,我們再嘗試擴充套件它,擴充套件成功。b 擴充套件成為 bcb

我們稱這個不斷找最長字尾迴文串的過程為字尾鏈跳躍

  1. 奇偶字典樹

我們可以用兩棵字典樹來儲存迴文串,一棵存長度為奇數的,一棵存長度為偶數的。我們可以用結點 \(0,1\) 分別表示偶數字典樹和奇數字典樹的根。在儲存迴文串時,我們只存一半。比如迴文串 abccba,我們在偶數字典樹上加入 \(0 \to\) c \(\to\) b \(\to\) a,這樣我們從下往上讀,讀到 \(0\) 後再讀下來就是原串。如果是 abcba,那我們在奇數字典樹上加入 \(0 \to\) c \(\to\) b \(\to\) a,這樣我們從下往上讀再讀回來,但最上面的邊只讀一次。

下圖是 zaacaac 的儲存方式:

  1. 建迴文樹

相關文章