对无序数组求中位数,是一个比较经典的问题了。
有很多种办法求。
这题是边添加边求中位数的。
所以每插入一个数就sort一遍复杂度太高显然不行。
还有一种利用大根堆小根堆,即平衡树来求,这种可以,这里不说。说另一种复杂度相当的,当常数教小的。
利用树状数组来求第K小。
建一个权值树状数组。例如有3,4,5,5,6四个数,那么
即树状数组中存的是某个区间的权值出现的次数。
由于这是一个32位无符号整型,范围过大必然使内存爆炸,所以需要离散化一下,先给原先的数组排一下序,就可以记录每个是是排在第几位,用这个排位来代替原值求,然后最后再转换回去。
所以就可以边插入边求得第,显然前
个数的中位数就更新到第
个数时的第
大了,因为我们只要
是奇数的。
那么显然第大的数,比如为
则必然是
,
表示区间和
详见代码注释:
#include<bits/stdc++.h>
#define endl '\n'
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int MX=20000+5;
using namespace std;
int cnt[MX];
int upd(int pos,int x)//更新权值树状数组
{
// a[pos]++;
for(;pos<MX;pos+=pos&-pos)
{
cnt[pos]+=x;
}
}
int find_vk(int k)//求第k个权值
{
int ans = 0,res = 0;
for(int i=13;i>=0;i--)//i=log(mx);
{
ans+=(1<<i);
if(ans>= MX||res+cnt[ans]>= k)ans-=(1<<i);
else res+=cnt[ans];
}
return ans+1;
}
struct node
{
int x,id;
bool operator<(const node&that)const
{
return x<that.x;
}
}p[MX];
int a[MX],c[MX];
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int n;
int t;
cin>>t;
while(t--)
{
memset(cnt,0,sizeof cnt);
int ca;
cin>>ca>>n;
rep(i,1,n)
{
int x;
cin>>x;
p[i].x=x;
p[i].id=i;
}
cout<<ca<<" "<<n/2+1<<endl;
int m=0;
sort(p+1,p+n+1);
rep(i,1,n)a[p[i].id]=i,c[i]=p[i].x;//对原数组离散化
rep(i,1,n)
{
upd(a[i],1);
if(i&1)
{
int k=(i+1)/2;
k=find_vk(k);
cout<<c[k]<<" ";
m++;
if(m%10==0)cout<<endl;
}
}
if(m%10)cout<<endl;
}
}


京公网安备 11010502036488号