题意:给n个有序的数字,三个操作:1、删除数字x;2、增加数字x;3、求i%5=3的数字之和(i为数字的下标)
思路:一开始想水一下,结果超时。先对所有输入的数字离散化,线段树维护区间上点的个数和5个sum值,区间合并的时候要注意:左儿子节点和父亲节点的关系很容易,右儿子合并的时候与左儿子中的点个数有关。
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<stdio.h>
#include<math.h>
#define LL __int64
#define N 100005
#define inf 0x7ffffff
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
char cins[N][10];
int cinx[N];
int a[2*N];
struct node
{
int l,r,cnt;
LL sum[5];
}tree[2*N*4];
void build(int o,int l,int r)
{
tree[o].l = l;
tree[o].r = r;
tree[o].cnt = 0;
for(int i = 0; i < 5; i++) tree[o].sum[i] = 0;
if(l == r) return ;
int m = (l + r)/2;
build(2*o,l,m);
build(2*o+1,m+1,r);
}
void pushup(int o)
{
tree[o].cnt = tree[2*o].cnt + tree[2*o+1].cnt;
for(int i = 0; i < 5; i++)
tree[o].sum[i] = tree[2*o].sum[i];
for(int i = 0; i < 5; i++)
tree[o].sum[(i+tree[2*o].cnt) % 5] += tree[2*o+1].sum[i];
}
void update(int o,int pos,int v)
{
if(tree[o].l == tree[o].r)
{
tree[o].sum[1] = v;
if(v == 0) tree[o].cnt--;
else tree[o].cnt++;
return ;
}
int m = (tree[o].l + tree[o].r)/2;
if(pos <= m) update(2*o,pos,v);
else update(2*o+1,pos,v);
pushup(o);
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int n;
while(scanf("%d",&n) != EOF)
{
int i,tot = 0;
for(i = 0; i < n; i++)
{
scanf("%s",cins[i]);
if(cins[i][0] != 's')
{
scanf("%d",&cinx[i]);
a[tot++] = cinx[i];
}
}
sort(a,a+tot);
tot = unique(a,a+tot) - a;
build(1,1,tot);
for(int i = 0; i < n; i++)
{
if(cins[i][0] == 's')
printf("%I64d\n",tree[1].sum[3]);
else
{
int pos = lower_bound(a,a+tot,cinx[i]) - a + 1;
//cout<<pos<<" "<<cinx[i]<<endl;
if(cins[i][0] == 'a')
update(1,pos,cinx[i]);
else update(1,pos,0);
}
}
}
return 0;
}