思路:
对于add(x),找到x的位置pos,将[pos,pos]区间加上x;对于del(x),找到位置pos,将[pos,pos]区间减去x。那么怎么求哪些数排完序后是余3的呢?
我们把原来的sum[k]表示线段树第k个区间的区间和,变为sum[k][0],sum[k][1],sum[k][2],sum[k][3],sum[k][4],表示线段树第k个区间中,下标余0,余1,余2,余3,余4的区间和。
那么怎么合并呢?并不是简单的sum[k][i]=sum[k<<1][i]+sum[k<<1|1][i]就可以的了。
正确的公式应该是sum[k][i]=sum[k<<1][i]+sum[k<<1|1][i-now],now是k<<1区间内的数的个数,所以我们再维护一个add[k]表示线段树的第k个区间的区间内有多少个数。所以sum[k][i]=sum[k<<1][i]+sum[k<<1|1][((i-add[k<<1)%5+5)%5]。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,tot;
int b[N],add[N<<2];
ll sum[N<<2][5];
struct number{int x,f;}num[N];
char str[10];
void change(int k,int l,int r,int v1,int v2,int pos)
{
if (l==r)
{
sum[k][1]+=(ll)v1;
add[k]+=v2;
return;
}
int mid=l+r>>1;
if (pos<=mid) change(k<<1,l,mid,v1,v2,pos);
else change(k<<1|1,mid+1,r,v1,v2,pos);
add[k]=add[k<<1]+add[k<<1|1];
for (register int i=0; i<=4; ++i)
{
int now=((i-add[k<<1])%5+5)%5;
sum[k][i]=sum[k<<1][i]+sum[k<<1|1][now];
}
}
int main(){
scanf("%d",&n);
for (register int i=1; i<=n; ++i)
{
scanf("%s",str+1);
if (str[1]=='a')
{
scanf("%d",&num[i].x); num[i].f=1;
b[++tot]=num[i].x;
}
else if (str[1]=='d')
{
scanf("%d",&num[i].x); num[i].f=-1;
}
else
{
num[i].f=0;
}
}
sort(b+1,b+tot+1);
tot=unique(b+1,b+tot+1)-b-1;
for (register int i=1; i<=n; ++i)
{
if (!num[i].f) printf("%lld\n",sum[1][3]);
else
{
int v1=num[i].x*num[i].f;
int v2=num[i].f;
int pos=lower_bound(b+1,b+tot+1,num[i].x)-b;
change(1,1,tot,v1,v2,pos);
}
}
return 0;
}