题目地址:
https://www.acwing.com/problem/content/description/248/
给定长度为
N
N
N的数列
A
A
A,然后输入
M
M
M行操作指令。
第一类指令形如C l r d
,表示把数列中第
l
∼
r
l∼r
l∼r个数都加
d
d
d。
第二类指令形如Q x
,表示询问数列中第
x
x
x个数的值。
对于每个询问,输出一个整数表示答案。
输入格式:
第一行包含两个整数
N
N
N和
M
M
M。
第二行包含
N
N
N个整数
A
[
i
]
A[i]
A[i]。
接下来
M
M
M行表示
M
M
M条指令,每条指令的格式如题目描述所示。
输出格式:
对于每个询问,输出一个整数表示答案。每个答案占一行。
数据范围:
1
≤
N
,
M
≤
1
0
5
1≤N,M≤10^5
1≤N,M≤105
∣
d
∣
≤
10000
|d|≤10000
∣d∣≤10000
∣
A
[
i
]
∣
≤
1
0
9
|A[i]|≤10^9
∣A[i]∣≤109
考虑用树状数组维护其差分数组 d d d,那么预处理部分相当于将第 i i i个数加上 x x x,在差分数组里对应着 d [ i ] d[i] d[i]加上 x x x, d [ i + 1 ] d[i+1] d[i+1]减去 x x x。将第 l ∼ r l\sim r l∼r里每个数加上 x x x,对应着 d [ l ] d[l] d[l]加上 x x x, d [ r + 1 ] d[r+1] d[r+1]减去 x x x;求第 k k k个数的值,等价于求 d d d里前 k k k个数的和。代码如下:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m, tr[N];
int lowbit(int x) {
return x & -x;
}
void add(int k, int x) {
for (int i = k; i <= n; i += lowbit(i)) tr[i] += x;
}
int sum(int k) {
int res = 0;
for (int i = k; i; i -= lowbit(i)) res += tr[i];
return res;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
add(i, x);
add(i + 1, -x);
}
while (m--) {
char op[2];
scanf("%s", op);
int x;
if (*op == 'Q') {
scanf("%d", &x);
printf("%d\n", sum(x));
} else {
int l, r;
scanf("%d%d%d", &l, &r, &x);
add(l, x);
add(r + 1, -x);
}
}
return 0;
}
预处理时间 O ( n log n ) O(n\log n) O(nlogn),每次操作时间复杂度 O ( log n ) O(\log n) O(logn),空间 O ( n ) O(n) O(n)。