洛谷P1168 中位数

方法一1:用两个优先队列,一个从小到大(k+1)A,堆顶元素就是中位数;一个从大到小B。每次来两个新数,小就放B,大就放A。前面的多了向后放,后面多了向前倒。

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
int n,a1;
priority_queue<int,vector<int> ,greater<int> >minheap;
priority_queue<int>maxheap;
int main() {
    scanf("%d%d",&n,&a1);
    printf("%d\n",a1);
    minheap.push(a1);
    for(int i=3; i<=n; i+=2) {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a>minheap.top())minheap.push(a);
        else maxheap.push(a);
        if(b>minheap.top())minheap.push(b);
        else maxheap.push(b); 
        while(maxheap.size()>=minheap.size()) {
            minheap.push(maxheap.top());
            maxheap.pop();
        }
        while(maxheap.size()<minheap.size()-1) {
            maxheap.push(minheap.top());
            minheap.pop();
        }
        printf("%d\n",minheap.top());
    }
    return 0;
}

方法二:求k大值,用权值线段数

//权值线段树,离散化数据后,在对应的位置插入1, 
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 230000
int a[N],b[N];
int n,m;
struct node {
    int l,r,sum;//sum,所有离散化后数字的权值和 
    int val;
} t[N*4];
inline void build(int p,int l,int r) {
    t[p].l=l,t[p].r=r;
    if(l==r)return;
    int m=(l+r)>>1;
    build(p<<1,l,m);
    build(p<<1|1,m+1,r);
}
void query(int p,int pos) {//查询从1到哪个点截至,权值和正好为pos 
    if(t[p].l==t[p].r) {
        printf("%d\n",t[p].val);
        return;
    }
    int x=t[p<<1].sum;//
    if(x>=pos)query(p<<1,pos);
    else query(p<<1|1,pos-x);
}
void Insert(int p,int pos,int val) { 
    if(t[p].l==t[p].r&&t[p].l==pos) {
        t[p].val=val;
        t[p].sum++; 
        return;
    }
    int m=(t[p].l+t[p].r)>>1;
    if(pos>m)Insert(p<<1|1,pos,val);
    else 
        Insert(p<<1,pos,val); 
    t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
    
}
int main() {
    cin>>n;
    m=(n+1)>>1;
    build(1,1,n);
    for(int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    int k=lower_bound(b+1,b+n+1,a[1])-b;
    Insert(1,k,a[1]);
    query(1,1);
    for(int i=1; i<m; i++) {
        k=lower_bound(b+1,b+n+1,a[i<<1])-b;
        Insert(1,k,a[i<<1]);
        k=lower_bound(b+1,b+n+1,a[i<<1|1])-b;
        Insert(1,k,a[i<<1|1]);
        query(1,i+1);
    }
    return 0;
}

方法三:权值线段树可以,树状数组当然行啦

但树状数组没法查询和的截至位置,用二分答案

//树状数组、二分答案, 
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 230000
int a[N],b[N],c[N];
int n,m;
int lowbit(int x){return x&-x; }
void add(int i,int val){
    for(;i<=n;i+=lowbit(i))
        c[i]+=val;	
}
int query(int i){// 求前i项的和 
    int ans=0;
    for(;i;i-=lowbit(i))ans+=c[i];
    return ans; 
}
int half(int val) {
    int l=1,r=n,mid,ans;
    while(l<=r){
        mid=(l+r)/2;
        if(query(mid)<val)l=mid+1;
        else ans=mid,r=mid-1;
    }
    return b[ans];
}
int main() {
    cin>>n;
    for(int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    int k=lower_bound(b+1,b+n+1,a[1])-b;
    add(k,1);
    printf("%d\n",a[1]);
    for(int i=1; i<=(n-1)/2; i++) {
        k=lower_bound(b+1,b+n+1,a[i<<1])-b;
        add(k,1);
        k=lower_bound(b+1,b+n+1,a[i<<1|1])-b;
        add(k,1);
        printf("%d\n",half(i+1));
    }
    return 0;
}

方法四,中位数,平衡树正好可以求,写不出来:(

猜你喜欢

转载自blog.csdn.net/lengxuenong/article/details/81542319