2020CCPC綿陽C題 Code a Trie 字典樹(簽到題)

@

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哦。

AC_CODE
思路很簡單,可惜我代碼寫的有點冗雜。
here

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章