题意
给你n个操作,分为三种分别是 : add a , del a ,sum,表示的是你可以在添加一个数,删除一个数,求下标 i % 5 == 3 的所有和是多少,注意当你删除一个点的时候,他后面的点的下标都会改变。
思路
由样例可以看出来需要用线段树,具体怎么用?由于线段树没有删除和增加的操作,所以我么把删除和增加离线下来,然后离散一下,把每次操作对应成线段树上的节点,那么每次删除和增加操作我们就可以对节点进行操作,增加就让节点变成他相对应的值,删除就让节点变成0,那么对于求下标i%5 == 3 的和要怎么去求呢?对于每一个节点我们维护两个东西一个是 num,一个是sum[5],num表示的是当前节点所管辖的区间里有多少个值,而sum[5]表示的是当前节点所管辖的区间里的下标%5 = 0,1,2,3,4的值,换句话说就是以当前节点开始的第1个值,第2个值…当前节点就是区间的第一个值,那么对于pushup来说,他的sum[i]的值其实就是左区间的sum[i]加上右区间sum[((i-sum左区间的有效数目)%5 + 5 ) % 5]
,仔细想想,如果你要区间合并的时候,左区间有3个数,那么你右区间的第一个数应该是4,而不是1,对吧。这样就好了,其实这题的难点就在于区间合并的时候,如何把右区间的第i个值是全区间的第几个值。
代码
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1e5+100;
char sh[maxn][10] ;
long long x[maxn] , a[maxn];
int cnt = 0;
struct Segtree
{
long long num[maxn<<2];
long long sum[maxn<<2][5];
void pushup(int rt)
{
for(int i = 0 ; i < 5 ; i++)
{
sum[rt][i] = sum[rt<<1][i] + sum[rt<<1|1][((i - num[rt<<1])%5 + 5)%5];
}
}
void build(int l,int r,int rt)
{
memset(sum[rt],0,sizeof(sum[rt]));
num[rt] = 0;
if(l == r) return ;
int m = (l+r)>>1;
build(lson);
build(rson);
}
void update(int pos,long long val,int op,int l,int r,int rt)
{
op ? ++num[rt]:--num[rt];
if(l == r)
{
sum[rt][0] = val * op;
return ;
}
int m = (l+r)>>1;
if(pos <= m) update(pos,val,op,lson);
else update(pos,val,op,rson);
pushup(rt);
}
}tree;
int main()
{
long long n;
while(scanf("%lld",&n)!=EOF)
{
cnt = 0;
for(int i = 0 ; i < n ;i++)
{
cin>>sh[i];
if(sh[i][0] != 's')
{
scanf("%lld",&a[i]);
x[cnt++] = a[i];
}
}
sort(x,x+cnt);
cnt = unique(x,x+cnt) - x;
tree.build(1,cnt,1);
for(int i = 0 ; i < n ;i++)
{
if(sh[i][0] == 'a')
{
int k = lower_bound(x,x+cnt,a[i]) - x + 1;
tree.update(k,a[i],1,1,cnt,1);
}
else if(sh[i][0] == 'd')
{
int k = lower_bound(x,x+cnt,a[i]) - x + 1;
tree.update(k,a[i],0,1,cnt,1);
}
else printf("%lld\n",tree.sum[1][2]);
}
//print(1,cnt,1);
}
return 0;
}