1. 程式人生 > 其它 >題解 P1486 【[NOI2004] 鬱悶的出納員】

題解 P1486 【[NOI2004] 鬱悶的出納員】

P1486 [NOI2004] 鬱悶的出納員

題目大意:

維護一個數據結構,有以下操作:

  1. 插入一個點,若該點的值小於規定下界,直接刪除;
  2. 把所有點的值加 \(k\)
  3. 把所有點的值減 \(k\) ,若有點得值小於下界,則刪除;
  4. 查詢第 \(k\) 的數,若沒有輸出 \(-1\)

最後還要輸出因小於下界被刪除的點得個數。

solution:

這熟悉的操作,我們直接上平衡樹。對於操作 \(1\) ,直接插入就好了。對於操作 \(2\)\(3\) ,暴力修改時間複雜度不允許,但我們發現加減操作都是對於整體的,所以我們開一個 \(delta\) 來記錄整體的加減。在我們插入新點時,把 \(k\)

減去 \(delta\) ,加入到樹中。取出點時加上 \(delta\) 。就降低了時間複雜度。

在進行操作 \(3\) 時,我們需要找到大於等於 \(min-delta\) 的最小數。然後刪除這段區間。

簡單推導一下:

對於 \(\forall k_i\) 滿足 \(k_i<min\) 的數會被刪掉,但這平衡樹中存的是 \(k_i-delta\) 的值,所以有 \(k_i+delta<min\) ,我們要刪除的值域為 \(k_i<min-delta\) 。但是我們要找到第一個不被刪的點,即右邊界的開區間,所以要找大於等於 \(min-delta\) 的最小值的位置作為右端點。

推畢[滑稽]

具體操作是找到右端點,將其轉到跟,將左端點轉到根的左兒子,這時左端點的右兒子即為要刪除的點,清空兒子即可。

操作 \(4\) 是基操,也不說了,但別忘了加上 \(delta\) ,若此時樹的大小 \(<k\) 即輸出 \(-1\)

細節處理:

一定要考慮哨兵產生的影響