题意:
刚开始有一个空集合。有三种操作:
1.往集合中加入一个集合中不存在的数 x
2.从集合中删除一个已经存在的数 x
3.计算集合的digest sum并输出。 digest sum求法:将集合中所有数从小到大排序,得到a1<a2<...<an。 digest sum = sum(ai) where i mod 5 = 3
数据范围:
N ( 1 <= N <= 105 )
1 <= x <= 109.
For any “add x” it is guaranteed that x is not currently in the set just before this operation.
For any “del x” it is guaranteed that x must currently be in the set just before this operation.
思路:
先将所有增加过的,删除过的数存下来,去重,搞成线段树。
每个结点(区间)里有两个东西,一个是 cnt,记录该区间的在集合中的元素的个数。一个是sum[i] , sum[i]:该区间序号%5等于i的存在于集合中的元素的总和。
插入和删除时维护即可。
代码:
int const maxn=1e5+5; struct node{ int cnt; ll sum[5]; }tree[maxn<<2]; int n,tot; int q[maxn],a[maxn]; char ope[maxn][15]; void build(int l,int r,int rt){ tree[rt].cnt=0; memset(tree[rt].sum,0,sizeof(tree[rt].sum)); if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void pushUp(int rt){ rep(i,0,4) tree[rt].sum[i]=tree[rt<<1].sum[i]+tree[rt<<1|1].sum[((5-tree[rt<<1].cnt%5)%5+i)%5]; } void update(int k,int pos,int num,int l,int r,int rt){ tree[rt].cnt+=k; if(l==r){ tree[rt].sum[0]+=(k*num); return; } int m=(l+r)>>1; if(pos<=m) update(k,pos,num,lson); else update(k,pos,num,rson); pushUp(rt); } int main(){ //freopen("test.in","r", stdin); while(scanf("%d",&n)!=EOF){ tot=0; rep(i,1,n){ scanf("%s",ope[i]); if(ope[i][0]!=‘s‘){ scanf("%d",&q[i]); a[tot++]=q[i]; } } sort(a,a+tot); tot=unique(a,a+tot)-a; if(tot==0) memset(tree[1].sum,0,sizeof(tree[1].sum)); else build(1,tot,1); rep(i,1,n){ int pos=lower_bound(a,a+tot,q[i])-a+1; if(ope[i][0]==‘a‘){ update(1,pos,q[i],1,tot,1); continue; } if(ope[i][0]==‘d‘){ update(-1,pos,q[i],1,tot,1); continue; } printf("%I64d\n",tree[1].sum[2]); } } //fclose(stdin); }
时间: 2024-10-16 09:59:37