安利一個黑科技,不知道是誰發明的(好像也有些年代了?)spa
其實這個黑科技的本質就是一個大根堆,不一樣的是 它支持刪除堆內任意元素,同時也支持堆的基本操做code
代碼以下:get
struct Heap{ priority_queue<int> q1,q2; inline void push(int x){q1.push(x);} inline void erase(int x){q2.push(x);} inline void pop(){for(;q2.size()&&q1.top()==q2.top();q1.pop(),q2.pop());if(q1.size())q1.pop();} inline int top(){for(;q2.size()&&q1.top()==q2.top();q1.pop(),q2.pop());return q1.top();} inline int top2(){int val,ret; val=top(),pop(),ret=top(),push(val); return ret;} inline int size(){return q1.size()-q2.size();} };
解釋一下兩個堆 \(q1\) 和 \(q2\) :it
\(q1\) 存儲了當前全部元素(包括未刪除元素)io
\(q2\) 存儲了 \(q1\) 中已刪除的元素class
咱們看到 push 操做,很日常,就是向 \(q1\) 中 \(push\) 一個新的元素bug
這就是這個黑科技的精華了,咱們向 \(q2\) 中 \(push\) 一個元素表示在 \(q1\) 中它已經被刪除了queue
這裏就要用到 \(q2\) 裏面的元素了,若是堆頂的元素已經被 \(erase\) 過,那麼它此時應該在 \(q2\) 中的堆頂總結
此時咱們把兩個堆一塊兒 \(pop\) 就行了,直到堆頂元素不一樣或者 \(q2\) 沒元素了top
這裏就是先進行和 \(pop\) 中相似的操做,刪除已經 \(erase\) 的元素,而後取出堆頂
有點騷,這個操做能夠取出堆中的次大值,而 \(top3\) 、\(top4\) 以此類推(雖然說不怎麼用到)
這個就是返回堆大小的,能夠知道堆當前真實大小就是 \(q1\) 大小減去 \(q2\) 大小
新技能 \(get\) !
可是注意一下,這裏咱們的 \(erase\) 操做必須合法, 不然會出現 \(bug\)
或者修改一下操做可能能夠支持不合法操做...但我本人以爲不大可能...