Sum of Medians

Sum of Medians

线段树

CodeForces 85D

题解:

先把数据离散化,为每个出现的数字在线段树里预留好位置。
线段树节点维护当前区间里有几个数字cnt,以及mod5分类的和sum[1] sum[2] … sum[5]
合并的时候左区间的sum对应加,右区间的根据lch.cnt来一个偏移然后再加。
注意,有一组数据长这样:

1
sum

开不开心,哈哈哈…

Code:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;
typedef long long LL;
const LL N = 200005;

char op[N][5]; 
LL d[N], tp[N], p[N];

struct Node{
    LL l,r,mid;
    LL cnt,sum[5];
} pool[N*4];

void print(LL x){
    puts("print:");
    Node &t=pool[x];
    D(t.l); D(t.r); D(t.cnt); E;
    for(LL i=0;i<5;i++){
        D(t.sum[i]);
    }
    E; E;
}

void update(LL x){
    Node &t=pool[x];
    if(t.l!=t.r){
        Node &lch=pool[x*2], &rch=pool[x*2+1];
        t.cnt=lch.cnt+rch.cnt;
        for(LL i=0;i<5;i++){
            t.sum[i]=lch.sum[i];
            t.sum[i]+=rch.sum[((i-lch.cnt)%5+5)%5];
        }
    }
}

void build(LL x,LL l,LL r){
    if(r<l) return;
    Node &t=pool[x]; 
    t.l=l; t.r=r; t.mid=(l+r)>>1;
    t.cnt=0; memset(t.sum,0,sizeof(t.sum));
    if(l!=r){
        build(x*2,t.l,t.mid); build(x*2+1,t.mid+1,t.r);
    }
}

void add(LL x,LL p,LL d){
    Node &t=pool[x];
    if(t.l==t.r){ t.cnt=1; t.sum[1]=d; }
    else{
        if(p<=t.mid) add(x*2,p,d);
        else add(x*2+1,p,d);
        update(x);
    }
//  print(x);
}

void del(LL x,LL p){
    Node &t=pool[x];
    if(t.l==t.r){ t.cnt=0; t.sum[1]=0; }
    else{
        if(p<=t.mid) del(x*2,p);
        else del(x*2+1,p);
        update(x);
    }
}

int main(){
    freopen("a.in","r",stdin);
    LL m,n=0; cin>>m;
    for(LL i=1;i<=m;i++){
        scanf("%s",op[i]);
        if(op[i][0]!='s'){
            cin>>d[i]; tp[n++]=d[i];
        }
    }
    sort(tp,tp+n); n=unique(tp,tp+n)-tp;
    build(1,1,n);
    for(LL i=1;i<=m;i++) p[i]=lower_bound(tp,tp+n,d[i])-tp+1;
    for(LL i=1;i<=m;i++){
        if(op[i][0]=='a'){
//          D(p[i]); D(d[i]); E;
            add(1,p[i],d[i]);
//          for(LL i=0;i<5;i++){
//              D(i); D(pool[1].sum[i]); E;
//          }
//          E;
        }
        else if(op[i][0]=='d'){
            del(1,p[i]);
        }
        else if(op[i][0]=='s'){
//          for(LL i=0;i<5;i++){
//              D(i); D(pool[1].sum[i]); E;
//          }
            cout<<pool[1].sum[3]<<endl;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值