树状数组 :区间修改,区间查询

树 状 数 组 : 区 间 修 改 , 区 间 查 询 树状数组 :区间修改,区间查询

一、树状数组是什么?

新手请参考 — — — — 》 》 ————》》

树状数组 数据结构详解与模板(可能是最详细的了)

夜深人静写算法(十三)- 树状数组

二、区间修改与区间查询

凡是涉及到区间修改,就必须用到 差 分 差分

求前缀和:

  • a p a_p ap 的前缀和: ∑ i = 1 p a [ i ] = ∑ i = 1 p ∑ j = 1 i d [ j ] \sum_{i=1}^{p}a[i]=\sum_{i=1}^{p}\sum_{j=1}^{i}d[j] i=1pa[i]=i=1pj=1id[j]

  • ∑ i = 1 p ∑ j = 1 i d [ j ] \sum_{i=1}^{p}\sum_{j=1}^{i}d[j] i=1pj=1id[j]中, d 1 d_1 d1 被用了 p p p 次, d 2 d_2 d2 被用了 p − 1 p-1 p1 次……那么我们

    可以写出:

    a p a_p ap 的前缀和: ∑ i = 1 p ∑ j = 1 i d [ j ] = ∑ i = 1 p d [ i ] × ( p − i + 1 ) = ( p + 1 ) × ∑ i = 1 p d [ i ] − ∑ i = 1 p d [ i ] × i \sum_{i=1}^{p}\sum_{j=1}^{i}d[j]=\sum_{i=1}^{p}d[i]\times(p-i+1)= \\ \\ \\ \\(p+1)\times\sum_{i=1}^{p}d[i]-\sum_{i=1}^{p}d[i]\times i i=1pj=1id[j]=i=1pd[i]×(pi+1)=(p+1)×i=1pd[i]i=1pd[i]×i

  • 那么我们可以用树状数组维护两个数组的前缀和:一个数组是 s u m 1 [ i ] = d [ i ] sum1[i]=d[i] sum1[i]=d[i],另一个数组是 s u m 2 [ i ] = d [ i ] × i sum2[i]=d[i]\times i sum2[i]=d[i]×i

区 间 修 改 区间修改

对于 t 1 t1 t1 数组的修改同上对 d d d 数组的修改。

对于 t 2 t2 t2 数组的修改也类似,我们给 t 2 [ l ] t2[l] t2[l] 加上 l × x l \times x l×x,给 t 2 [ r + 1 ] t2[r + 1] t2[r+1] 减去 ( r + 1 ) × x (r + 1) \times x (r+1)×x

A C c o d e AC code ACcode

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+5;
int n,q,a[maxn],maxx,b[maxn],c[maxn];

inline int lowbit(int a)
{
	return a&(-a);
}
inline void update(int x,int y)
{
	for(int i=x;i<=n;i+=lowbit(i))
	{
		b[i]+=y;
		c[i]+=x*y;
	}
}
inline void range_update(int l,int r,int x)
{
	update(l,x);
	update(r+1,-x);
}
inline int query(int x)
{
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
	{
		ans += (x+1) * b[i] - c[i];
	}
	return ans;
}
inline int range_query(int l,int r)
{
	return query(r)-query(l-1);
}
signed main()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		update(i,a[i]-a[i-1]);
	}
	for(int i=1;i<=q;i++)
	{
		int abc,x,y,z;
		cin>>abc;
		if(abc==1)
		{
			cin>>x>>y>>z;
			range_update(x,y,z);
		}
		else
		{
			cin>>x>>y;
			cout<<range_query(x,y)<<endl;
		}
	}
	return 0;
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值