PK的小学数学题-区间第k大板子

不知道已经成为大学生的你是否还记得中位数这个东西,我们似乎很少再用到它,今天  就想让你做一下这个小学数学题。

初始你手里什么也没有,接下来  会按顺序给你  个数。当你手中的数的个数为奇数时,你需要告诉  你手里这堆数的中位数是多少。

输入格式

第一行一个正整数  ,表示给你的数的个数。

接下来一行  个整数,表示依次给你的这些数  。

输出格式

输出  行,每行一个整数,表示答案。

当  为奇数时  ,当  为偶数时  ,其中除法为下取整。

样例

样例输入1

5
1 2 3 4 5

样例输出1

1
2
3

样例输入2

6
4 9 1 2 7 -66666

样例输出2

4
4
4

数据范围与提示

 

 

本题Idea来自2018年暑期集训期间与  的交流

#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define MN 200005
int n,m,a[MN],v[MN],id[MN],l,r,k,root[MN],cnt;
//a:输入的数 id:离散化的编号 root:各个历史版本的根
struct tree{
    int Ls,Rs,sum;
}Tree[MN*20];
//Ls、Rs:左右子树 sum:区间中数的数量
void change(int num,int &x,int l,int r){//注意这个'&'
    Tree[cnt]=Tree[x];x=cnt;cnt++;
    //建一个新节点,以便修改
    Tree[x].sum++;
    if(l==r) return;
    if(id[mid]>=num) change(num,Tree[x].Ls,l,mid);
        else change(num,Tree[x].Rs,mid+1,r);
       //改变需要改变的子节点
}
int ask(int i,int j,int num,int l,int r){
    if(l==r) return l;
    int tmp=Tree[Tree[j].Ls].sum-Tree[Tree[i].Ls].sum;
    if(tmp>=num) return ask(Tree[i].Ls,Tree[j].Ls,num,l,mid);
        else return ask(Tree[i].Rs,Tree[j].Rs,num-tmp,mid+1,r);
}//差分后查询
int main(){
    scanf("%d",&n);
    cnt=1;
    for(int i=1;i<=n;i++) {scanf("%d",&a[i]);v[i]=a[i];}
    sort(a+1,a+1+n);
    int N=unique(a+1,a+1+n)-a-1;
    for(int i=1;i<=N;i++)
        id[i]=a[i];
    //离散化
    for(int i=1;i<=n;i++){
        root[i]=root[i-1];//要共用上一个版本的节点
        change(v[i],root[i],1,N);
    }
    for(int i=1;i<=n;i+=2){
        printf("%d\n",id[ask(root[0],root[i],i/2+1,1,N)]);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章