树状数组实现 区间修改+区间查询




树状数组的本职:单值修改+区间查询


对于区间修改     首先想到的就是线段树   可是线段树的代码太tm长了    是真的懒得写    然后就学习了一下如何用状数组实现   区间修改+区间查询




差分数组


对于一个数组a     其差分数组定义为     C[i] = a[i] - a[i-1]( i>0 )&&C[0] = a[0]       

我们很容易看出    a[i] = C[0]+C[1]+C[2]+......+C[i]

然后   我们想实现区间修改就可以借助差分数组实现      

如果我们要实现对数组a    区间 [l,r]内的元素 +v

借助差分数组   只需使 C[l]+=v,C[r+1] -=v 即可





为什么可以这样实现呢     我们来看式子

a[1]+a[2]+...+a[n]

= (c[1]) + (c[1]+c[2]) + ... + (c[1]+c[2]+...+c[n]) 

= n*c[1] + (n-1)*c[2] +... +c[n]

= n * (c[1]+c[2]+...+c[n]) - (0*c[1]+1*c[2]+...+(n-1)*c[n])





由公式可以发现    我们要进行区间修改和区间查询只需要再维护一个数组 C2[i] = (i-1)*C[i]

对于         a[1]+a[2]+...+a[n]   =   n*read(C,n) - read(C2,n)




这样就可以进行区间修改和区间查询操作做了      因为我们同时进行修改数组C,C2    所以复杂度还是n*log(n)

而且比线段树快得多    




题目链接:http://codevs.cn/problem/1082/






代码实现:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
#include <math.h>
#include <bitset>
#include <climits>
using namespace std; 
typedef long long ll;
const int maxn=200000+10;
ll D1[maxn];
ll D2[maxn];
ll num[maxn];
ll n;
void add(ll D[],int k,ll num){
	while (k<=n){
		D[k]+=num;
		k+=(k&-k);
	}
}
ll read(ll D[],ll k){
	ll sum=0;
	while (k){
		sum+=D[k];
		k-=(k&-k);
	}
	return sum;
}
int main (){
	scanf ("%lld",&n);
	for (int i=1;i<=n;i++){
		scanf ("%lld",&num[i]);
		add(D1,i,num[i]-num[i-1]);
		add(D2,i,(i-1)*(num[i]-num[i-1]));
	}
	ll t;
	scanf ("%lld",&t);
	while (t--){
		ll m;
		scanf ("%lld",&m);
		if(m==1){
			ll l,r,v;
			scanf ("%lld%lld%lld",&l,&r,&v);
			add(D1,l,v);
			add(D1,r+1,-v);
			add(D2,l,v*(l-1));
			add(D2,r+1,-v*r);
		}
		else{
			ll l,r;
			scanf ("%lld%lld",&l,&r);
			ll sum1=(l-1)*read(D1,l-1)-read(D2,l-1);
			ll sum2=r*read(D1,r)-read(D2,r);
			printf ("%lld\n",sum2-sum1);
		}
	}
	return 0;
} 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值