[Codeforces 666E]Forensic Examination(廣義字尾自動機 + 線段樹合併 + 樹上倍增)
阿新 • • 發佈:2019-01-13
Address
Meaning
- 給定一個字串
和
- 有 個詢問,每個詢問給出四個引數 、 、 、
- 求 的子串 在 、 、…、 中的哪個串中出現的次數最多
- 如果出現次數最多的有多個串則取編號最小的
- 對於每組詢問輸出編號和出現次數
- , , ,
- 時限 6s ,空限 768MB
Solution
- 首先把所有的 和 放在一起建立廣義 SAM ,下面就對這個 SAM 對應的 Parent 樹進行討論
- 下面我們定義「黑點」為對 集合有貢獻的點(即 SAM 構建過程中,不是被拆解出的所有狀態點)
- 第一個問題:對於樹上的已知節點 以及已知區間 ,如何知道 這些串中,哪個串出現狀態 的次數最多(相同者取最小編號),以及出現次數
- 根據 Parent 樹的性質,狀態 的 集合可以用 的子樹內所有黑點的某些東西表示出來
- 又根據 SAM 的性質,一個黑點對應原串的一個字首。相應地,在廣義 SAM 上,一個黑點對應原串集合的 Trie 樹上根到一個點的路徑
- 可以在每個黑點上,用一個
vector
儲存這個黑點對應了字串集合 中哪些串的字首 - 以下把一個黑點上的 vector 記憶體的 內的字串編號記作 內的某種顏色
- 我們的做法出來了:這個問題就是求 的子樹內哪種顏色出現次數最多(相同則取最小編號顏色)以及出現次數
- 可以使用線段樹合併
或者可持久化線段樹解決這個問題 - 對每個點開一棵線段樹,下標為顏色,每個節點存出現次數最多的顏色及出現次數,對於每個點 ,通過線段樹合併從 的子節點的資訊合併到點 的資訊
- 到現在,我們已經解決了第一個問題
- 第二個問題:已知區間 ,如何找到子串 在 SAM 上對應的狀態點
- 如果是 對應的狀態點,那麼要找的點顯然是 的長度為 的字首對應的黑點
- 而根據 Parent 樹的性質, 對應的點是 對應點的祖先,且每個點的父親節點的 都嚴格小於自己的
- 於是,如果 對應的狀態點為 ,那麼我們要做的就是找到 的祖先中,離 最遠的,滿足 的點
- 可以使用樹上倍增找到這個點
- 這樣我們的做法就出來了:先通過線段樹合併預處理 Parent 樹每個點的子樹內資訊,詢問時通過樹上倍增找到 對應的狀態