题解 SP16254 【RMID2 - Running Median Again】

紫题

2018-11-25 10:37:24

Solution

### 双倍经验:SP15376 题意:动态维护中位数 维护两个堆,一个大根堆,一个小根堆,每个堆存储序列中的n/2个数 大根堆存第1 - cnt/2大的数,小根堆存第cnt/2+1 - cnt大的数 例如: 插入 5 2 3 1 4 大根堆:2 1 小根堆:3 4 5 当cnt为偶数时,中位数就是小根堆的堆顶 当cnt为奇数时,中位数就是小根堆堆顶和大根堆堆顶,取最小值即可 每次插入的时候和当前中位数比较,如果比中位数大就插入小根堆,否则插入大根堆 任何时候,当两个堆大小不平衡时(大根堆>小根堆 或 小根堆>大根堆+1),就将一个堆的堆顶取出放 到另一个堆里 **这种做法有个名字:对顶堆** $Code:$ ``` #include<cstdio> #include<queue> using namespace std; priority_queue<int>p; //大根堆 存储第1-mid priority_queue<int,vector<int>,greater<int> >q; //小根堆 存储第mid+1-n int temp,cnt,t; //cnt为当前序列的数的数量 int main(){ scanf("%d",&t); while(t){ scanf("%d",&temp); if(temp==0){ //清空 while(!q.empty()) q.pop(); while(!p.empty()) p.pop(); cnt=0; t--; } else if(temp==-1){ //删除堆顶元素 if(cnt&1){ printf("%d\n",q.top()); q.pop(); } else{ //由于下面的调整,大根堆的堆顶元素一定不大于小根堆堆顶元素 printf("%d\n",p.top()); p.pop(); } cnt--; } else{ //插入 int mid=(q.empty())?0:q.top(); if(temp>mid) q.push(temp); else p.push(temp); cnt++; if((cnt&1)&&p.size()>q.size()){ //大根堆 > 小根堆 int temp0=p.top(); p.pop(); q.push(temp0); } else if((cnt&1)==0&&q.size()>p.size()){ //小根堆 > 大根堆+1 int temp0=q.top(); q.pop(); p.push(temp0); } } } return 0; } ```