树状数组 差分 区间查询 区间修改 T3 243. 一个简单的整数问题2 - AcWing题库
给定一个长度为 的数列 ,以及 条指令,每条指令可能是以下两种之一:
C l r d
,表示把 都加上 。Q l r
,表示询问数列中第 个数的和。
对于每个询问,输出一个整数表示答案。
输入格式
第一行两个整数 。
第二行 个整数 。
接下来 行表示 条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
,
,
输入样例:
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
输出样例:
4
55
9
15
思路
区间查询和区间修改。 区间修改可以用差分技巧来实现, 那么怎么在此基础上实现区间查询呢? 列举一个区间和看看是什么样的: 每个数由若干项 的和组成, 而区间和则是把整个求和。 可以把这些数扩充为一个矩形后, 整个矩形的总和为 。 观察一下多出来的部分, 也可以用一个式子来描述: 。
故可以通过相减的方式来求出区间和。我们只需要建立两个对于差分数组a的前缀和树状数组 tr1 和 tr2, tr1中维护 的前缀和, tr2中维护 的前缀和。
输出时, 对于区间 , 为 再减去左区间 。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL tr1[N], tr2[N];
int a[N];
int n,m;
int lowbit(int x)
{
return x & -x;
}
void add(LL tr[], int u, LL x)
{
for(int i = u; i <= n;i += lowbit(i)) tr[i] += x;
}
LL sum(LL tr[], int u)
{
LL res = 0;
for(int i = u; i; i -= lowbit(i)) res += tr[i];
return res;
}
LL prefix_sum(int u)
{
return sum(tr1, u) * (u + 1) - sum(tr2, u);
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n;i ++) cin >> a[i];
for(int i = 1; i <= n;i ++)
{
LL b = a[i] - a[i - 1];
add(tr1, i, b);
add(tr2, i, (LL)b * i);
}
while(m--)
{
char s[2];
int l,r,d;
cin >> s >> l >> r;
if(s[0] == 'Q')
printf("%lld\n", prefix_sum(r) - prefix_sum(l - 1));
else {
cin >> d;
add(tr1, l, d), add(tr2, l, d * l);
add(tr1, r + 1, -d), add(tr2, r + 1, (r + 1) * -d);
}
}
return 0;
}