题意
给定长度为N的数列A,然后输入M行操作指令。
第一类指令形如“C l r d”,表示把数列中第l~r个数都加d。
第二类指令形如“Q X”,表示询问数列中第x个数的值。
对于每个询问,输出一个整数表示答案。
分析
如果这题不是使用线段树,而是使用树状数组来解决,怎么做呢?怎么思考呢?
树状数组仅支持单点修改和区间查询,但这题是要求区间修改和单点查询,好像跟树状数组反着来的。。。
仔细观察一下,其实把A[l]到A[r]都加d,就是把l到r这个区间中的数都加d, r+1到n这个区间中的数都减d,因此可以使用一个额外数组B来维护区间的变化, 至于查询第x个数,就是A[x]+ B[1]~B[x]
注意
这题序列元素的范围是10亿,因此有些变量需要使用long long
代码
#include <iostream>
#include <cstring>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
//a为存储数据的数组,b为树状数组
ll a[N];
int b[N];
//n为序列长度,m为操作指令次数
int n, m;
//lowbit操作
int lowbit(int x) {
return x & -x;
}
//区间查询
ll sum(int x) {
ll ans = 0;
while (x) {
ans += b[x];
x -= lowbit(x);
}
return ans;
}
//单点修改
void add(int x, int v) {
while (x <= n) {
b[x] += v;
x += lowbit(x);
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);//输入序列
while (m--) {
char op[2];
scanf("%s", op);
if (op[0] == 'C') {
int l, r, d;
scanf("%d%d%d", &l, &r, &d);
//b[l]加d,相当于a[l]~a[n]都加d
add(l, d);
//b[r + 1]减d,相当于a[r + 1]~a[n]都减d
add(r + 1, -d);
} else {
int x;
scanf("%d", &x);
printf("%lld\n", a[x] + sum(x));
}
}
}