区间修改区间查询【树状数组】

>Link

ybtoj区间修改区间查询


>解题思路

很经典的线段树模板,其实也可以用树状数组做

考虑差分, t i = a i − a i − 1 t_i=a_i-a_{i-1} ti=aiai1,那显然 a i = ∑ j = 1 i t j a_i=\sum_{j=1}^it_j ai=j=1itj
把查询的区间 [ l , r ] [l,r] [l,r] 转换成查询 [ 1 , l ] [1,l] [1,l] [ 1 , r ] [1,r] [1,r]
s u m l = a 1 + a 2 + . . . + a l = ( t 1 ) + ( t 1 + t 2 ) + . . . + ( t 1 + t 2 + . . . + t l ) = ( t 1 + t 2 + . . . + t l ) ∗ l − ( t 1 ∗ 0 + t 2 ∗ 1 + . . . + t l ∗ ( l − 1 ) ) sum_l=a_1+a_2+...+a_l=(t_1)+(t_1+t_2)+...+(t_1+t_2+...+t_l)=(t_1+t_2+...+t_l)*l-(t_1*0+t_2*1+...+t_l*(l-1)) suml=a1+a2+...+al=(t1)+(t1+t2)+...+(t1+t2+...+tl)=(t1+t2+...+tl)l(t10+t21+...+tl(l1))
我们就可以维护两个树状数组,一个正常的存 t i t_i ti,另一个存 t i ∗ ( i − 1 ) t_i*(i-1) ti(i1)
(这样的思想就是,把与 l l l 有关的系数转换一下变成与自身有关的系数)


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define N 1000010
using namespace std;

int n, q;
LL a[N], t[N], tt[N], ans;

void add_t (int x, LL val)
{
	for (; x <= n; x += x & (-x))
	  t[x] += val; 
}
void add_tt (int x, LL val)
{
	for (; x <= n; x += x & (-x))
	  tt[x] += val; 
}
LL ask_t (int x)
{
	LL ret = 0;
	for (; x; x -= x & (-x)) ret += t[x];
	return ret;
}
LL ask_tt (int x)
{
	LL ret = 0;
	for (; x; x -= x & (-x)) ret += tt[x];
	return ret;
}
LL sum (int x)
{
	LL ret = ask_t (x) * (LL)x;
	ret -= ask_tt (x);
	return ret;
}

int main()
{
	int type, l, r; LL x;
	scanf ("%d%d", &n, &q);
	for (int i = 1; i <= n; i++)
	{
		scanf ("%lld", &a[i]);
		add_t (i, a[i] - a[i - 1]);
		add_tt (i, ((LL)i - (LL)1) * (a[i] - a[i - 1]));
	}
	for (int i = 1; i <= q; i++)
	{
		scanf ("%d", &type);
		if (type == 1)
		{
			scanf ("%d%d%lld", &l, &r, &x);
			add_t (l, x), add_t (r + 1, -x);
			add_tt (l, ((LL)l - (LL)1) * x);
			add_tt (r + 1, -x * (LL)r);
		}
		else
		{
			scanf ("%d%d", &l, &r);
			printf ("%lld\n", sum (r) - sum (l - 1));
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值