1. 程式人生 > >【NOI導刊2010】黑匣子的題解——對頂堆的應用

【NOI導刊2010】黑匣子的題解——對頂堆的應用

這道題就是說,維護一個序列的兩種操作:

1.插入一個數.

2.k+1之後查詢這串序列的第i小.

注:開始k為0.

所以這道題是如何用堆來維護的呢?

我們可以維護兩個堆,一個大根堆和一個小根堆,初始時都為空,然後我們把大根堆作為序列比第k個數小的那一段,吧小根堆作為另一段.

那麼我們就可以維護這道題了,在操作1時將這個數與大根堆的堆頂比較,若插入的書更大,則插入到後面的小根堆中,否則將大根堆堆頂彈出插入到小根堆中,再將輸入的數插入大根堆中.

操作2時直接把小根堆堆頂彈出就可以了.

這就是一種被稱為“對頂堆”的方法.

那麼程式碼如下:

#include<bits/stdc++.h>
using namespace std;
#define TLE priority_queue
int n,m,a[200001],b[200001];
void into(){
  scanf("%d%d",&m,&n);
  for (int i=1;i<=m;i++) scanf("%d",&a[i]);
  for (int i=1;i<=n;i++) scanf("%d",&b[i]);
  sort(b+1,b+1+n);
}
TLE<int>maxq;
TLE<int,vector<int>,greater<int> >minq;
int main(){
  into();
  int k=1,j=1;
  for (int i=1;i<=m;i++){
    if (k==1||maxq.top()<=a[i]) minq.push(a[i]);
    else {minq.push(maxq.top());maxq.pop();maxq.push(a[i]);}
    while (b[j]==i){
      printf("%d\n",minq.top());
      maxq.push(minq.top());minq.pop();
      j++;k++;
    }
  }
  return 0;
}

這是早期作品,具體是怎麼樣的本人也不記得了,但是思路就是這樣的,可能有一些細節上的問題.