NC214362 第k小
题目链接
关键点:
1、观察题目,要求每次输出第k小的数,我们如果对这个数组进行排序,那么比第k小的数(x)还大的数,是没有可能在未来成为第k小的数,分析如下:
如果此时插入一个比x大的数,那么第k小的数还为x
如果此时插入一个比x小的数,那么第k小的数只能为x前面的数(比x还小)
2、因此每次要求求第k小的数时,我们将比k大的数给扔掉,不再继续判断,这种既可以排序,又可以扔掉大的数的为大顶堆,那么可以直接用优先队列
完整代码
# include <iostream>
# include <queue>
# include <cstdio>
using namespace std;
int n, m, k;
priority_queue<int>q;
int main()
{
cin>>n>>m>>k;
for (int i=1; i<=n; i++)
{
int x;
cin>>x;
q.push(x);
}
for (int i=1; i<=m; i++)
{
int x;
cin>>x;
// cout<<"top = "<<q.top()<<endl;
if (x == 2)
{
if (q.size()<k)
cout<<"-1"<<endl;
else
{
while (q.size()!=k)
q.pop();
cout<<q.top()<<endl;
}
}
else
{
int y;
cin>>y;
q.push(y);
}
}
return 0;
}
NC50940 Running Median
题目链接
关键点:
1、题目要求每次输入为奇数个时,输出中位数大小,我们用一个大顶堆存比当前中位数小的元素,一个小顶堆存比当前中位数大的元素,并且保持这两个顶堆元素个数相同
2、原因:每次求出奇数个数的中位数(x),接下来再插入元素,之后的中位数在该中位数的左右进行偏移,如果比x小,那么从小于x中的最大值中为中位数,比x大,那么从大于x中的最小值里去找
3、维护两个堆,如果两堆元素个数相同,中位数为各自top值的平均数,如果哪一方多一个,那么就为那一方的top值,如果当将一个元素插入一个堆中时,该堆个数多于另一个堆的1个时,将多的堆的top元素加入另一个堆里
完整代码
# include <iostream>
# include <cstdio>
# include <queue>
using namespace std;
int t, pos;
int a[10000+10];
int main()
{
cin>>t;
while (t--)
{
int xu, n;
pos = 0;
priority_queue<int>d;
priority_queue<int, vector<int>, greater<int> >x;
cin>>xu>>n;
int f, mid;
cin>>f;
x.push(f);
a[++pos] = f;
mid = f;
for (int i=2; i<=n; i++)
{
cin>>f;
// cout<<"mid = "<<mid<<endl;
if (f<mid)
{
d.push(f);
if (d.size()-x.size() > 1)
{
x.push(d.top());
d.pop();
}
}
else
{
x.push(f);
if (x.size() - d.size() > 1)
{
d.push(x.top());
x.pop();
}
}
// cout<<x.size()<<" "<<d.size()<<endl;
int ds = d.size(), xs = x.size();
if (ds-xs == 1)
mid = d.top();
else if (xs-ds == 1)
mid = x.top();
else
mid = (x.top()+d.top())/2;
if (i%2)
a[++pos] = mid;
}
cout<<xu<<" "<<pos<<endl;
for (int i=1; i<=pos; i++)
{
if (i%10)
cout<<a[i]<<" ";
else
cout<<a[i]<<endl;
}
cout<<endl;
}
return 0;
}