洛谷 P1168 中位数
给一个序列a,求前1,3,5......数的中位数
用\(S[]\)来存\(Ai\)这个数出现了几次,但是\(Ai<=10^9\),如果直接建好树,那就直接爆掉了。所以我们动态开点,就要每次插入一个路径,如果路径上的数没出现过,那么就要插入这个点。当读进去一个数\(X\),看有没有到叶子节点,如果到了,那么\(S[k]++\),再更新节点,如果没到,那么就开一个新的点来存\(X\)出现的次数,所以我们需要两个数组\(lc[]\)和\(rc[]\)来存左右儿子。访问时也很简单,只要进行递归就行了,不过要注意,如果左儿子个数比要访问的\(X\)数小,也就是当\(X>S[lc[k]]\)时,我们要访问右儿子,这时候是一个新的区间,所以\(X\)要变成\(X-S[lc[k]]\)。
完整代码
#include <iostream>
using namespace std;
const int N=1e9;
int n,s[5000000],lc[5000000],rc[5000000],nc;
int insert(int &k,int l,int r,int v)
{
if (!k)nc++,k=nc;
if (l==r)
{
s[k]++;
return 0;
}
int mid=l+r>>1;
if (v<=mid)insert(lc[k],l,mid,v);
else insert(rc[k],mid+1,r,v);
s[k]=s[lc[k]]+s[rc[k]];
}
int query(int k,int l,int r,int x)
{
if (l==r)return l;
int mid=l+r>>1;
if (x<=s[lc[k]])return query(lc[k],l,mid,x);
else return query(rc[k],mid+1,r,x-s[lc[k]]);
}
int main()
{
int x,rt=0;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>x;
insert(rt,1,N,x);
if (i%2==1)
cout<<query(1,1,N,(i+1)/2)<<endl;
}
return 0;
}