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;
}

 

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