题目地址:
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)。