题解 P9176 [COCI2022-2023#4] Vrsta

题意

有一个序列,初始为空。

有 $n$ 次操作,每次添加 $k$ 个值为 $a$ 的数到序列中。

对于每次操作,你需要输出当前序列的中位数,中位数有 $2$ 个输出较小值。

分析

$a$ 较大,离线离散化后再处理。

统计每个 $a$ 出现的次数,可以用树状数组。

设当前加入的数个数为 $c$,那么中位数即第 $\left\lceil\dfrac{c+1} 2\right\rceil$。

设中位数为 $x$,那么小于等于 $x$ 的个数必须大于等于 $\left\lceil\dfrac{c+1} 2\right\rceil$。

个数具有单调性,所以二分。

离散化复杂度 $O(n \log n)$,总体复杂度 $O(n \log^2 n)$。

注意事项

记得开 long long

代码

//the code is from chenjh
#include<cstdio>
#include<cstring>
#include<cassert>
#include<algorithm>
#define MAXN 200002
using namespace std;
typedef long long LL;
template<typename T>
struct fenwick_tree{//树状数组。
    public:
        fenwick_tree(int _SIZE=0):SIZE(_SIZE){dt=new T[SIZE+1]();memset(dt,0,sizeof(T)*(SIZE+1));}
        fenwick_tree(const fenwick_tree& y):SIZE(y.size()),dt(new T[y.size()+1]){memcpy(dt,y.get_dt(),sizeof(T)*(SIZE+1));}
        ~fenwick_tree(){delete[] dt;}
        const T&operator [] (const int&x)const{assert(0<x&&x<=SIZE);return dt[x];}
        fenwick_tree&operator = (const fenwick_tree&y){if(this!=&y){SIZE=y.size();T*new_dt=new T[SIZE+1]();memcpy(new_dt,y.get_dt(),sizeof(T)*(SIZE+1));delete[] dt;dt=new_dt;}return *this;}
        void resize(int _SIZE){T*new_dt =new T[_SIZE+1]();memcpy(new_dt,dt,sizeof(T)*((SIZE<_SIZE?SIZE:_SIZE)+1));delete[] dt;dt=new_dt,SIZE=_SIZE; }
        void clear(){SIZE=0;delete[] dt;dt=new T[SIZE+1]();memset(dt,0,sizeof(T)*(SIZE+1));}
        int size()const{return SIZE;}
        T* get_dt()const{return dt;}
        void add(int x,const T&v){assert(0<x&&x<=SIZE);for(;x<=SIZE;x+=x&-x)dt[x]+=v;}
        T sum(const int l,const int r)const{assert(0<l&&l<=r&&r<=SIZE);return sum(r)-sum(l-1);}
    private:
        T*dt;
        int SIZE;
        T sum(int x)const{assert(0<=x&&x<=SIZE);T ret(0);for(;x;x^=x&-x)ret+=dt[x];return ret;}
};
int n,k[MAXN],a[MAXN],b[MAXN];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&k[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    int m=unique(b+1,b+n+1)-b-1;//离散化。
    fenwick_tree<LL> T(m);
    LL c=0;
    for(int i=1;i<=n;i++){
        c+=k[i],T.add(lower_bound(b+1,b+m+1,a[i])-b,k[i]);
        int l=1,r=m;
        for(int mid;l<r;){//二分答案。
            if(T.sum(1,mid=(l+r)>>1)>=((c+1)>>1)) r=mid;
            else l=mid+1;
        }
        printf("%d\n",b[l]);
    }
    return 0;
}
posted @ 2024-01-26 21:04  Chen_Jinhui  阅读(15)  评论(0)    收藏  举报  来源