NOI online 2021 島嶼探險
場上寫了個被卡常的時間\(n\log^2 n\),空間 $n\log n $ 做法,洛谷上開O2才能過
我們先考慮對所有\(d_i< b_j\) 計算 \(j\) 對 \(i\) 的貢獻。首先可以把詢問 \(i\) 拆成
並且和插入一起離線下來按下標的順序排好序。
那麼我們維護一個\(0-1trie\),按順序把 \(a_j\) 插入\(trie\)中,查詢就是從高到低遍歷 \(d_i\) 的每一位
如果 \(d_i\) 當前位爲0,顯然 \(trie\) 上只能走與 \(c_i\) 當前位相同的兒子。
如果 \(d_i\) 當前位爲1,對與 \(c_i\) 當前位相同的兒子 \(u0\) 進行子樹查詢 \(d_i<b_j\)(\(a_j\) 在\(u_0\)子樹內) 的個數。因爲此時 \(c_i\) 和 \(a_j\) 異或起來這一位比 \(d_i\) 小,後面 \(a_j\) 無論如何取值都符合條件。然後再遞歸處理與 \(c_i\) 當前位不同的兒子 \(u1\) 。
子樹查詢可以在\(trie\)樹上每個節點開個vector,插入的時候把 \(b_j\) 存到經過的每個節點的\(vector\)上,詢問也存在vector上,最後對於每個vector按push進來的順序用動態開點線段樹進行插入和詢問。
對 \(d_i\ge b_j\) 的情況,可以當作是對每個 \(b_j\) 計算有多少個 \(b_j\le d_i\) 且 \(c_i\oplus a_j\leq b_j\),也就是交換一下插入和詢問,按上面的做法做,然後再反過來考慮每個插入的 \(c_i,d_i\) 會被哪些詢問的 \(b_j\) 統計到。也就是在每個vector裏把存下來的插入計算出有多少個詢問能統計到它,逆序做就行了。
由於一次插入和詢問對於trie樹上每個節點的vector最多隻會push進一個元素,每個vector最多隻有n個元素,所以每次計算完一個節點的vector的插入和詢問就清空,空間複雜度是 \(n\log n\) 的。總共有 \(n\log n\) 個元素,線段樹每次$\log n \(,時間複雜度是\)n\log^2 n$。