題解 P1486 【[NOI2004] 鬱悶的出納員】
阿新 • • 發佈:2021-07-29
P1486 [NOI2004] 鬱悶的出納員
題目大意:
維護一個數據結構,有以下操作:
- 插入一個點,若該點的值小於規定下界,直接刪除;
- 把所有點的值加 \(k\) ;
- 把所有點的值減 \(k\) ,若有點得值小於下界,則刪除;
- 查詢第 \(k\) 大的數,若沒有輸出 \(-1\) ;
最後還要輸出因小於下界被刪除的點得個數。
solution:
這熟悉的操作,我們直接上平衡樹。對於操作 \(1\) ,直接插入就好了。對於操作 \(2\) 、 \(3\) ,暴力修改時間複雜度不允許,但我們發現加減操作都是對於整體的,所以我們開一個 \(delta\) 來記錄整體的加減。在我們插入新點時,把 \(k\)
在進行操作 \(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\) 。
細節處理:
一定要考慮哨兵產生的影響