一、单点修改、区间查询
例: 已知一个数列,有两种操作:
1、将某一个数加上x
2、求出某区间每一个数的和
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
int tr[N], a[N];
int n, tt;
int lowbit(int x) {
return x & -x;
}
void add(int x, int c) {
for(int i = x; i <= n; i += lowbit(i)) {
tr[i] += c;
}
}
LL sum(int x) {
LL res = 0;
for(int i = x; i > 0; i -= lowbit(i)) {
res += tr[i];
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> tt;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
add(i, a[i]);
}
while(tt --) {
int op;
cin >> op;
if(op == 1) {
int x, k;
cin >> x >> k;
add(x, k);
} else {
int l, r;
cin >> l >> r;
cout << sum(r) - sum(l - 1) << '\n';
}
}
return 0;
}
二、区间修改、单点查询
例: 已知一个数列,有两种操作:
1、将某区间每一个数加上x
2、求出某一个数的值
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
int tr[N], a[N];
int n, tt;
int lowbit(int x) {
return x & -x;
}
void add(int x, int c) {
for(int i = x; i <= n; i += lowbit(i)) {
tr[i] += c;
}
}
LL sum(int x) {
LL res = 0;
for(int i = x; i > 0; i -= lowbit(i)) {
res += tr[i];
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> tt;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
add(i, a[i] - a[i - 1]);
}
while(tt --) {
int op;
cin >> op;
if(op == 1) {
int l, r, x;
cin >> l >> r >> x;
add(l, x);
add(r + 1, -x);
} else {
int x;
cin >> x;
cout << sum(x) << '\n';
}
}
return 0;
}
三、区间修改、区间查询(需要额外的辅助数组)
例: 已知一个数列,有两种操作:
1、将某区间每一个数加上x
2、求出某区间每一个数的和
计算推导
b$_1$ = a$_1$
b$_2$ = a$_2$ - a$_1$
…
b$_n$ = a$_n$ - a$_{n-1}$
数组a的前缀和: S = a$_1$ + a$_2$ + … + a$_n$
a$_0$ = 0
a$_1$ = b$_1$
a$_2$ = b$_1$ + b$_2$
a$_3$ = b$_1$ + b$_2$ + b$_3$
…
a$_n$ = b$_1$ + b$_2$ + b$_3$ + … + b$_n$
S = $\sum_1^n$a$_i$ = (n + 1) * (b$_1$ + b$_2$ + … + b$_n$) - (1 * b$_1$ + 2 * b$_2$ + … + n * b$_n$)
即S = (n + 1) * $\sum_1^n$b$_i$ - $\sum_1^n$i * b$_i$
可用tr1维护bi的前缀和,tr2维护i * bi的前缀和
则在代码中S可表示为(x + 1) * sum(tr1, x) - sum(tr2, x)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL a[N], tr1[N], tr2[N];
int n, tt;
int lowbit(int x) {
return x & -x;
}
void add(LL tr[], int x, LL c) {
for(int i = x; i <= n; i += lowbit(i)) {
tr[i] += c;
}
}
LL sum(LL tr[], int x) {
LL res = 0;
for(int i = x; i > 0; i -= lowbit(i)) {
res += tr[i];
}
return res;
}
LL presum(LL x) {
return (x + 1) * sum(tr1, x) - sum(tr2, x);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> tt;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
LL u = a[i] - a[i - 1];
add(tr1, i, u);
add(tr2, i, (LL) i * u);
}
while(tt --) {
int op;
cin >> op;
if(op == 2) {
int l, r;
cin >> l >> r;
cout << presum(r) - presum(l - 1) << '\n';
} else {
int l, r, c;
cin >> l >> r >> c;
add(tr1, l, c);
add(tr1, r + 1, -c);
add(tr2, l, l * c);
add(tr2, r + 1, (r + 1) * -c);
}
}
return 0;
}