✅ 优先队列 priority_queue 
更多关于优先队列的知识,请跳转至:https://en.oi-wiki.org/lang/pb-ds/pq/ 
 
大顶堆:priority_queue<int> pq
 
小顶堆:priority_queue<int, vector<int>, greater<>> pq
 
 
相关例题 :
__gnu_pbds :: priority_queue附: 官方文档地址——复杂度及常数测试 
1 2 3 #include  <ext/pb_ds/priority_queue.hpp>  using  namespace  __gnu_pbds;__gnu_pbds ::priority_queue<T, Compare, Tag, Allocator> 
 
模板形参 :
T : 储存的元素类型 
Compare : 提供严格的弱序比较类型 
Tag 是 __gnu_pbds 提供的不同的五种堆,Tag 参数默认是 pairing_heap_tag ,这五种分别是:
pairing_heap_tag :配对堆,官方文档认为在非原生元素(如自定义结构体/ std :: string / pair ) 中,配对堆表现最好 
binary_heap_tag :二叉堆,官方文档认为在原生元素中二叉堆表现最好,不过我测试的表现并没有那么好 
binomial_heap_tag :二项堆,二项堆在合并操作的表现要优于配对堆*但是其取堆顶元素的 
rc_binomial_heap_tag :冗余计数二项堆 
thin_heap_tag :除了合并的复杂度都和 Fibonacci 堆一样的一个 tag 
 
 
Allocator :空间配置器,由于 OI 中很少出现,故这里不做讲解 
 
由于本篇文章只是提供给学习算法竞赛的同学们,故对于后四个 tag 只会简单的介绍复杂度,第一个会介绍成员函数和使用方法。
 
经作者本机测试堆的基础操作,结合 GNU 官方的复杂度测试,Dijkstra 测试,都表明:至少对于 OIer 来讲,除了配对堆(即默认 tag)的其他四个 tag 都是鸡肋,要么没用,要么常数大到不如 std 的,且有可能造成 MLE,故这里只推荐用默认的配对堆。同样,配对堆也优于 algorithm 库中的 make_heap() 。
构造方式 要注明命名空间因为和 std 的类名称重复。
1 2 3 4 5 __gnu_pbds ::priority_queue<int > __gnu_pbds::priority_queue<int , greater<int > > __gnu_pbds ::priority_queue<int , greater<int >, pairing_heap_tag> __gnu_pbds ::priority_queue<int >::point_iterator id;  id = q.push (1 ); 
 
成员函数 
push() : 向堆中压入一个元素,返回该元素位置的迭代器。 
pop() : 将堆顶元素弹出。 
top() : 返回堆顶元素。 
size() 返回元素个数。 
empty() 返回是否非空。 
modify(point_iterator, const key) : 把迭代器位置的 key 修改为传入的 key ,并对底层储存结构进行排序。 
erase(point_iterator) : 把迭代器位置的键值从堆中擦除。 
join(__gnu_pbds :: priority_queue &other) : 把 other 合并到 *this 并把 other 清空。 
 
时间复杂度 使用的 tag 决定了每个操作的时间复杂度:
239. 滑动窗口最大值 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
1 2 3 4 5 6 7 8 9 10 11 输入:nums = [1 ,3 ,-1 ,-3 ,5 ,3 ,6 ,7 ], k = 3  输出:[3 ,3 ,5 ,5 ,6 ,7 ] 解释: 滑动窗口的位置                最大值 ---------------               ----- [1   3   -1 ] -3   5   3   6   7        3   1  [3   -1   -3 ] 5   3   6   7        3   1   3  [-1   -3   5 ] 3   6   7        5   1   3   -1  [-3   5   3 ] 6   7        5   1   3   -1   -3  [5   3   6 ] 7        6   1   3   -1   -3   5  [3   6   7 ]      7  
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Solution  {public :    vector<int > maxSlidingWindow (vector<int >& nums, int  k)   {                  priority_queue<pair<int , int >, vector<pair<int , int >>, less<>> pq;         for  (int  i = 0 ; i < k; i++) {             pq.emplace (nums[i], i);         }         vector<int > ans{pq.top ().first};         for  (int  i = k; i < nums.size (); i++) {             pq.emplace (nums[i], i);             while  (pq.top ().second <= i - k) {                 pq.pop ();             }             ans.push_back (pq.top ().first);         }         return  ans;     } }; 
 
295. 数据流的中位数 中位数 是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
例如 arr = [2,3,4] 的中位数是 3 。 
例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。 
 
实现 MedianFinder 类:
MedianFinder() 初始化 MedianFinder 对象。 
void addNum(int num) 将数据流中的整数 num 添加到数据结构中。 
double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 输入 ["MedianFinder" , "addNum" , "addNum" , "findMedian" , "addNum" , "findMedian" ] [[], [1 ], [2 ], [], [3 ], []] 输出 [null, null, null, 1.5 , null, 2.0 ] 解释 MedianFinder medianFinder = new  MedianFinder (); medianFinder.addNum (1 );     medianFinder.addNum (2 );     medianFinder.findMedian ();  medianFinder.addNum (3 );     medianFinder.findMedian ();  
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class  MedianFinder  {private :    priority_queue<int > left;                               priority_queue<int , vector<int >, greater<>> right;  public :    MedianFinder () {}     void  addNum (int  num)   {                  if  (left.size () == right.size ()) {             right.push (num);             left.push (right.top ());             right.pop ();         } else  {             left.push (num);             right.push (left.top ());             left.pop ();         }     }     double  findMedian ()   {         return  (left.size () + right.size ()) % 2                     ? left.top ()                    : static_cast <double >(left.top () + right.top ()) / 2 ;     } }; 
 
480. 滑动窗口中位数 中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。
例如:
[2,3,4],中位数是 3 
[2,3],中位数是 (2 + 3) / 2 = 2.5 
 
给你一个数组 nums ,有一个长度为 k  的窗口从最左端滑动到最右端。窗口中有 k  个数,每次窗口向右移动 1  位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。
给出 nums  = [1,3,-1,-3,5,3,6,7],以及 k  = 3。
1 2 3 4 5 6 7 8 窗口位置                      中位数 ---------------               ----- [1   3   -1 ] -3   5   3   6   7        1   1  [3   -1   -3 ] 5   3   6   7       -1   1   3  [-1   -3   5 ] 3   6   7       -1   1   3   -1  [-3   5   3 ] 6   7        3   1   3   -1   -3  [5   3   6 ] 7        5   1   3   -1   -3   5  [3   6   7 ]      6  
 
 因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]。
1️⃣ 哈希表 + 逻辑删除 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 class  Solution  {public :    priority_queue<int > left;                               priority_queue<int , vector<int >, greater<>> right;      unordered_map<int , int > mp;                             double  get (int  k)   {         if  (k % 2 )             return  left.top ();         else              return  ((long  long )left.top () + right.top ()) / 2.0 ;     }     vector<double > medianSlidingWindow (vector<int >& nums, int  k)   {         for  (int  i = 0 ; i < k; i++) {             int  x = nums[i];             if  (left.size () == right.size ()) {                 right.push (x);                 left.push (right.top ());                 right.pop ();             } else  {                 left.push (x);                 right.push (left.top ());                 left.pop ();             }         }         vector<double > ans{get (k)};         for  (int  i = k; i < nums.size (); i++) {             int  balance = 0 ;                           int  l_num = nums[i - k];             mp[l_num]++;             if  (!left.empty () && l_num <= left.top ()) {                 balance++;             } else  {                 balance--;             }                          if  (!left.empty () && nums[i] <= left.top ()) {                 left.push (nums[i]);                 balance--;             } else  {                 right.push (nums[i]);                 balance++;             }                          if  (balance > 0 ) {                 left.push (right.top ());                 right.pop ();             } else  if  (balance < 0 ) {                 right.push (left.top ());                 left.pop ();             }                          while  (!left.empty () && mp[left.top ()] > 0 ) {                 mp[left.top ()]--;                 left.pop ();             }             while  (!right.empty () && mp[right.top ()] > 0 ) {                 mp[right.top ()]--;                 right.pop ();             }             ans.push_back (get (k));         }         return  ans;     } } 
 
2️⃣ 懒删除堆 
本题等价于:295. 数据流的中位数 + 懒删除堆
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 template <typename  T, typename  Compare = less<T>>class  LazyHeap {    priority_queue<T, vector<T>, Compare> pq;     unordered_map<T, int > remove_cnt;      size_t  sz = 0 ;           void  apply_remove ()   {         while  (!pq.empty () && remove_cnt[pq.top ()] > 0 ) {             remove_cnt[pq.top ()]--;             pq.pop ();         }     } public :    size_t  size ()   {         return  sz;     }          void  remove (T x)   {         remove_cnt[x]++;          sz--;     }          T top ()   {         apply_remove ();         return  pq.top ();     }          T pop ()   {         apply_remove ();         sz--;         T x = pq.top ();         pq.pop ();         return  x;     }          void  push (T x)   {         if  (remove_cnt[x] > 0 ) {             remove_cnt[x]--;          } else  {             pq.push (x);         }         sz++;     }          T push_pop (T x)   {         apply_remove ();         pq.push (x);         x = pq.top ();         pq.pop ();         return  x;     } }; class  Solution  {public :    vector<double > medianSlidingWindow (vector<int >& nums, int  k)   {         int  n = nums.size ();         vector<double > ans (n - k + 1 )  ;         LazyHeap<int > left;          LazyHeap<int , greater<int >> right;          for  (int  i = 0 ; i < n; i++) {                          int  in = nums[i];             if  (left.size () == right.size ()) {                 left.push (right.push_pop (in));             } else  {                 right.push (left.push_pop (in));             }             int  l = i + 1  - k;             if  (l < 0 ) {                  continue ;             }                          if  (k % 2 ) {                 ans[l] = left.top ();             } else  {                 ans[l] = ((long  long ) left.top () + right.top ()) / 2.0 ;             }                          int  out = nums[l];             if  (out <= left.top ()) {                 left.remove (out);                 if  (left.size () < right.size ()) {                     left.push (right.pop ());                  }             } else  {                 right.remove (out);                 if  (left.size () > right.size () + 1 ) {                     right.push (left.pop ());                  }             }         }         return  ans;     } };