>Link
ybtoj区间修改区间查询
>解题思路
很经典的线段树模板,其实也可以用树状数组做
考虑差分,
t
i
=
a
i
−
a
i
−
1
t_i=a_i-a_{i-1}
ti=ai−ai−1,那显然
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−(t1∗0+t2∗1+...+tl∗(l−1))
我们就可以维护两个树状数组,一个正常的存
t
i
t_i
ti,另一个存
t
i
∗
(
i
−
1
)
t_i*(i-1)
ti∗(i−1)
(这样的思想就是,把与
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;
}