CF85D Sum of Medians

思路:
对于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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值