@
Gym102822C Code a Trie: 字典樹
鏈接
傳送門: here
題意
建議先瀏覽一遍題面代碼。
給你一段構建字典樹的代碼:每個節點隨機賦予一個權值,保證每個點權值都不相同。
再給你\(n(1e5)\)個字符串及其執行\(query\)函數后的結果,問滿足這些結果的字典樹最少節點數量。
每組數據字符串長度和不超過\(100000\)。
思路
首先將字符串按照權值(即\(query\)后得到的答案)排序並依次插入進字典樹。
對於具有相同權值字符串,他們返回答案的節點一定在字典樹\(rt\)到\(lca\)路徑上的某點處。
對於只有一個字符串的權值,其\(lca\)就是他自己的末尾節點。
將所有權值對應字符串集合的\(lca\)標記一下,可以肯定的是每個節點只能作為一種權值的\(lca\)。
假設有\(m\)個字符串權值相同,他們在\(lca\)后的出邊是:\(a,b,c,d\)。
可以肯定的是這四條出邊對應節點的子樹內不能有其他權值的\(lca\)節點。
我們將\(lca\)這些出邊對應的節點標記為不可能存在的節點,即\(die[node]=1\)。
確定一下無解情況:
- 兩個字符串相同但是權值不同。
- 多個權值對應的\(lca\)是同一節點。
- \(rt\)到某個\(lca\)路徑上存在\(die\)節點。
再來確定一下\(dfs\)貪心求解過程,遍歷到節點\(u\):
- 如果\(u\)的某條出邊的子樹內沒有\(lca\)節點,這個子樹全部扔掉。
- 如果\(u\)的某條出邊的子樹內有多個\(lca\)節點,那么節點\(u\)必須保留。
- 如果\(u\)存在若干條出邊的子樹內僅有\(1\)個\(lca\)節點:
-- 如果\(u\)是\(lca\)節點,這些子樹只需要保留一個節點即可,即\(u\)的兒子。
-- 如果\(u\)不是\(lca\)節點,可以完全拋棄一個子樹,剩余子樹處理同上。
為什么這樣貪心是對的呢?一條條解答:
- 這條出邊子樹內沒有\(lca\)節點,我的\(query\)不會走到這里,當然可以全部拋棄掉呀。
- 如果節點\(u\)不保留,代表\(u\)的子樹都不保留,那這對應兩個\(lca\)的\(query\)勢必會得到同一個答案才對,互相矛盾,所以\(u\)必須保留。
- 這里分了兩個情況:
-- 這些子樹內只有一個\(lca\)節點,那么我詢問的時候提前結束肯定最優,也不會影響別人,所以只需要保留\(u\)的兒子。
-- 因為\(u\)不是\(lca\),我可以把一個子樹內的\(lca\)節點直接提到\(u\)來。
\(over!\)稍微復雜點的簽到題罷了。
備注
下標寫錯找了一年bug。
godie(st[sid[j]], len[sid[j]]);
---->
godie(st[j], len[j]);
想die哦。
時間復雜度:\(O(nlog(n))\)
空間復雜度:\(O(\sum |s| *26)\)
AC_CODE
思路很簡單,可惜我代碼寫的有點冗雜。
here