1. 程式人生 > >洛谷 - P1801 - 黑匣子 - 對頂堆

洛谷 - P1801 - 黑匣子 - 對頂堆

平衡樹 學習 真的 動態 name truct n) for top

這道題是提高+省選-的難度,做出來的話對數據結構題目的理解會增加很多。

可以使用一種叫做對頂堆的東西,對頂堆是在線維護第n小的logn的算法。大概的思路是,假如我們要找的是第n小,我們就維護一個大小為n的(位於下方的)大頂堆,(位於上方的)小頂堆中每個元素都比大頂堆的大。在這道題中,n不變時每次有新的比他小的就把堆頂彈出到對頂(也就是小頂堆)的堆頂,每次n擴大的時候就從(上面的)小頂堆裏取出堆頂放進大頂堆的堆頂……

但是看樣子應該其他平衡樹也是可以解決這個問題的。比如支持快速名次的splay?還有完全另一個維度復雜的主席樹(區間第k大)。

這道題應該是對頂堆最簡單了。但是明顯是用別的數據結構更好,因為對頂堆的第n小只能慢慢變……這樣真的不如splay……(當然啦!splay這麽復雜,你怎麽不用主席樹呢?主席樹還區間第k大呢?)

Pdalao說了一個,可以用BST來維護,每個節點維護左子樹的名次,那麽找k的時候就可以判斷是進入左子樹還是右子樹了,陷入思考……其實還是要旋轉來保持平衡樹的特性……

真實的遞歸學習法,一個兩個都不會。


動態維護第k小也可以交給各類平衡樹去完成。 而且k還可以不斷改。

對頂堆用來維護一種頂堆只會不斷擴大的情形非常方便。和之前的動態求中位數一個道理。

這裏我們根據題目命名為“黑匣子堆”:註意每次頂堆擴大時,假如底堆有元素則優先從底堆獲取。

#include<bits/stdc++.h>
using
namespace std; struct Black_Box_Heap{ //top_heap has the min element,bottom heap has the max element priority_queue<int,vector<int>,less<int> > top_heap; priority_queue<int,vector<int>,greater<int> > bottom_heap; int i; Black_Box_Heap(){i
=0;} void add(int value){ if(top_heap.size()<=i){ top_heap.push(value); } else{ if(value<top_heap.top()){ bottom_heap.push(top_heap.top()); top_heap.pop(); top_heap.push(value); } else{ bottom_heap.push(value); } } } int get(){ int t=top_heap.top(); i++; while(top_heap.size()<=i&&!bottom_heap.empty()){ top_heap.push(bottom_heap.top()); bottom_heap.pop(); } return t; } }bbh; int a[200005]; int main(){ int m,n; scanf("%d%d",&m,&n); for(int i=1;i<=m;i++){ scanf("%d",&a[i]); } int j=1; for(int i=1;i<=n;i++){ int u; scanf("%d",&u); while(u>=j){ bbh.add(a[j]); j++; } printf("%d\n",bbh.get()); } }

洛谷 - P1801 - 黑匣子 - 對頂堆