题解:中位数

传送门

首先考虑的是二叉搜索树,每次查找当前排名(i+1)/2的数。但是对于某些数据,其递归层数过多,会导致爆栈。

那么显然可以用Treap或Splay。

这里考虑线段树:

由于线段树是一种平衡树,所以一定保证能跑出来。

对于线段树,我们基于二叉搜索树的查找方法并介于线段树平衡的性质求解。

对于线段树的每一个节点,我们记其大小为num,并记录其左边最大值和右边最小值。

在插入时我们考虑存入一个有序数列,保证其根节点的元素单调递增。

则其左边最大值和右边最小值分别为左儿子右端点和右儿子左端点。

在插入时,若:

   当前值x=左最大=右最小,显然x=根节点。

我们令根节点的num+1.

   当前值x>左最大,往右放;反之,往左放。

在查询时:

  就相当于结合了二叉搜索树的找排名,和线段树的单点修改的样子。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define lson l,mid,rn<<1
#define rson mid+1,r,rn<<1|1
using namespace std;
int n,a[100010],b[100010],size;
struct cym{
    int num;
    int l_size,r_size;
}tree[400010];
void update(int rn)
{
    tree[rn].num=tree[rn<<1].num+tree[rn<<1|1].num;
    tree[rn].l_size=tree[rn<<1].l_size;tree[rn].r_size=tree[rn<<1|1].r_size;
}
void build(int l,int r,int rn)
{
    if(l==r)
    {
        tree[rn].l_size=tree[rn].r_size=b[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    update(rn);
}
void add(int x,int now)
{
    if(tree[now].l_size==tree[now].r_size&&tree[now].l_size==x)
    {
        tree[now].num++;
        return;
    }
    if(x>tree[now<<1].r_size)
    add(x,now<<1|1);
    else
    add(x,now<<1);
    update(now);
}
int find(int l,int r,int rn,int rank)
{
    if(l==r)
    return tree[rn].l_size;
    int mid=(l+r)>>1;
    int ans=0;
    if(rank<=tree[rn<<1].num)
    ans=find(lson,rank);
    else
    ans=find(rson,rank-tree[rn<<1].num);
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    size=unique(b+1,b+1+n)-(b+1);
    build(1,size,1);
    for(int i=1;i<=n;i++)
    {
        add(a[i],1);
        if(i&1)
        printf("%d\n",find(1,size,1,(i+1)>>1));
    }
}

猜你喜欢

转载自www.cnblogs.com/zzh666/p/9181274.html