题解 | #Running Median#被格式卡了好久,写一篇题解吧。
Running Median
https://ac.nowcoder.com/acm/problem/50940
经典对顶堆写法就可以了。依次加入元素,左边为大根堆,右边为小根堆。每次加入一个新的元素的时候判断一下是加入右边还是左边。由于保证了左右堆的数量差距<=1,所以一共三种情况我选择了枚举。另外空格和换行的问题有被恶心到,直接上代码吧。
#include<cstring>
#include<algorithm>
#include<iostream>
#include<bitset>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
int a[4];
int main()
{
int t; cin >> t;
while (t--)
{
int m, n; scanf(" %d%d", &m, &n);
printf("%d %d\n", m, n + 1 >> 1);
int cnt = 1;
priority_queue<int, vector<int>, less<int>>p;//大根堆
priority_queue<int, vector<int>, greater<int>>q;//小根堆
for (int i = 1; i <= n; i++)
{
int x; scanf(" %d", &x);
if (n == 1 || n == 2) { printf("%d", x); break; }//n=1和n=2只需要输出第一个元素就可以了,特殊样例直接打死,懒得想了。
if (i <= 2)
{
a[i] = x; continue;
}
if (i == 3)
{
printf("%d ", a[1]);//因为要先保证p和q都不能为空才能进入下面写的那些if语句,不然会报错。所以在n>=3的时候先把前俩个元素按大小加进去就行了。
sort(a + 1, a + 1 + 2);
p.push(a[1]); q.push(a[2]);
}
if (p.size() < q.size())//不想耗费脑细胞了,直接三种情况讨论了。。最简捷明了了,虽然代码又臭又长我承认。
{
if (x <= q.top())p.push(x);
if (x > q.top())
{
int tmp = q.top();
q.pop();
q.push(x);
p.push(tmp);
}
}
else if (p.size() == q.size())
{
if (x <= q.top())p.push(x);
if (x > q.top())
{
int tmp = q.top();
q.pop();
q.push(x);
p.push(tmp);
}
}
else if (p.size() > q.size())
{
if (x >= p.top())q.push(x);
if (x < p.top())
{
int tmp = p.top();
p.pop();
p.push(x);
q.push(tmp);
}
}
if (p.size() - q.size() == 1 && i != n && i != n - 1) { cnt++; printf("%d%c", p.top(), cnt % 10 == 0 ? '\n' : ' '); }//如果不是最后一个元素该咋咋地
else if (p.size() - q.size() == -1 && i != n && i != n - 1) { cnt++; printf("%d%c", q.top(), cnt % 10 == 0 ? '\n' : ' '); }
else if (p.size() - q.size() == 1 && (i == n || i == n - 1)) { cnt++; printf("%d", p.top()); }
//这里是特判了最后一个元素,因为只讨论奇数,所以可能i=n或者n-1反正只会进来一次无所谓了。最后一个元素不要空格。是否换行由t的值来判定。
else if (p.size() - q.size() == -1 && (i == n || i == n - 1)) { cnt++; printf("%d", q.top()); }
}
if (t > 0)printf("\n");//如果不是最后一次样例就换行,否则不要。
}
return 0;
}
写在最后:请不要喷我,我知道我代码真的又臭又长,跟那些大佬的优美代码仿佛不是一种语言,但我真的尽力了。缝缝补补地打补丁就是这样。。。