双堆求动态中位数

acwing 106.动态中位数

https://www.acwing.com/problem/content/108/

 

 这题可以用两个堆完成,用一个大根堆存储中位数左边的数,用一个小根堆存储中位数右边的数。

因此,我们需要维护两个堆的一个性质:

两个堆的数字数目需要相同(为了方便,将中位数也算在左边的大根堆中,所以实际上大根堆会比小根堆的数目多一个)。

①每次读入一个数,判断大根堆$down$是否为空,若空, 就插入。或者当前的数$x$是否小于大根堆$down$的堆顶,是就插入,否则就插入小根堆$up$。

②然后判断大根堆$down$的数目是不是比小根堆$up$的数目$+1$还要大,如果还要大,就需要将大根堆$down$的堆顶元素放入小根堆$up$中。

③然后判断小根堆$up$的数目是不是比大根堆$down$的数目大,是就将小根堆$up$的堆顶元素插入大根堆$down$中。

然后在总数目为奇数的时候,大根堆$down$的堆顶元素就是当前序列的中位数。

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <queue>
 5 
 6 using namespace std;
 7 
 8 
 9 
10 int main(){
11     int T;
12     cin >> T;
13     while(T --)
14     {
15         int L, m;
16         cin >> L >> m;
17         
18         priority_queue<int> down;
19         priority_queue<int, vector<int>, greater<int>> up;
20         int cnt = 0;
21         cout << L << " " << (m + 1) / 2 << endl;
22         
23         for(int i = 1 ; i <= m ; i ++)
24         {
25             int x;
26             cin >> x;
27             
28             if(down.empty() || x <= down.top())down.push(x);
29             else up.push(x);
30             
31             
32             if(down.size() > up.size() + 1)up.push(down.top()), down.pop();
33             if(up.size() > down.size())down.push(up.top()), up.pop();
34             
35             if(i % 2)
36             {
37                 cout << down.top() << " ";
38                 if( ++ cnt % 10 == 0)cout << endl;
39             }
40             
41         }
42         if(cnt % 10)cout << endl;
43     }
44     return 0;
45 }

 

posted @ 2020-03-31 16:31  dzcixy  阅读(557)  评论(0)    收藏  举报