uva 12501 - Bulky process of bulk reduction 线段树 不好想

27 篇文章 0 订阅
3 篇文章 0 订阅
//uva 12501 - Bulky process of bulk reduction
/*
题目地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3945

题意:
一个数列a[],初始化所有元素为100,有两种操作:
1、更新操作:将一段连续的区间[i,j]都加上一个值v:
			 a[i]+v;	a[i+1]+v;	...		a[j]+v;
2、查询操作:查询a[i]*1 + a[i+1]*2 + a[i+2]*3 + ... + a[j]*(j+1)的值

	
思路:
线段树维护两个值s,sum:
s为区间[l,r]的a[l]+a[l+1]+a[l+2]+...a[r]的和
sum为区间[l,r]的a[l]*1+a[l+1]*2+a[l+2]*3+...+a[r]*(r+1)的和
这样如果包含有某个区间
那就这样区间的值就是sum+s*num,s为该区间[l,r]的右孩子,num为该区间左孩子中在[l,r]中的个数。


比如查询区间[2,4],
a[2] = 100;a[3]=100; a[4]=100;
线段树中:
sum[2,2] = a[2,2];  sum[3,4] = a[3,3]*1 + a[4,4]*2;
-->sum[2,4] = a[2,2]*1 + a[3,3]*1 + a[4,4]*2
线段树中区间[2,4]的右孩子[3,4]的s[3,4] = a[3,3] + a[4,4],左孩子[1,2]在[2,4]的个数为1
所以 ans=  a[2,2]*1 + a[3,3]*1 + a[4,4]*2 +(a[3,3] + a[4,4])*1
		=  a[2,2]*1 + a[3,3]*2 + a[4,4]*3

说的有点乱,画一画再参考下代码就会明白。
*/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define N 100005
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define int64 long long

int64 s[N<<2],sum[N<<2],add[N<<2];

void Pushup(int rt,int m){
	s[rt] = s[rt<<1] + s[rt<<1|1];
	sum[rt] = sum[rt<<1] + s[rt<<1|1] *(m-(m>>1)) + sum[rt<<1|1];
}

void Pushdown(int rt,int m){
	if(add[rt]){
		int64 a = m-(m>>1);
		int64 b = (m>>1);
		add[rt<<1] += add[rt];
		add[rt<<1|1] += add[rt];
		s[rt<<1] += add[rt] * a;
		s[rt<<1|1] += add[rt] * b;
		sum[rt<<1] += (1+a)*a/2*add[rt];
		sum[rt<<1|1] += (1+b)*b/2*add[rt];
		add[rt] = 0;
	}
}

void Build(int rt,int l,int r){
	add[rt] = 0;
	if(l == r){
		s[rt] = sum[rt] = 100;
		return;
	}
	int mid = (l + r) >> 1;
	Build(lson);
	Build(rson);
	Pushup(rt,r-l+1);
}

void Update(int rt,int l,int r,int L,int R,int val){
	int64 v = (int64)val;
	if(L <= l && R >= r){
		add[rt] += v;
		s[rt] += v * (r-l+1);
		sum[rt] += v * (r-l+2) * (r-l+1) / 2;
		return;
	}
	Pushdown(rt,r-l+1);
	int mid = (l + r) >> 1;
	if(L <= mid) Update(lson,L,R,val);
	if(R > mid ) Update(rson,L,R,val);
	Pushup(rt,r-l+1);
}

int64 Query(int rt,int l,int r,int L,int R){
	if(L <= l && R >= r){
		return s[rt]*(l-L)+sum[rt];
	}
	Pushdown(rt,r-l+1);
	int mid = (l + r) >> 1;
	int64 res = 0;
	if(L <= mid) res += Query(lson,L,R);
	if(R > mid ) res += Query(rson,L,R);
	return res;
}

int main(){
	int i,T,n,m,ca = 1;
	char op[10];
	int a,b,c;
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&n,&m);
		printf("Case %d:\n",ca++);
		Build(1,1,n);
		while(m--){
			scanf("%s",op);
			if(op[0] == 'q'){
				scanf("%d %d",&a,&b);
				printf("%lld\n",Query(1,1,n,a,b));
			}
			else{
				scanf("%d %d %d",&a,&b,&c);
				Update(1,1,n,a,b,c);
			}
		}
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值