Sum of Medians
线段树
题解:
先把数据离散化,为每个出现的数字在线段树里预留好位置。
线段树节点维护当前区间里有几个数字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;
}
}
}