树状数组Day1题解(3/7)+小结
1.单点修改,区间查询(简单)
较水,咕咕
2.区间修改,单点查询(较为简单)
将一个区间的数同时加上一个x,自然想到差分序列 ( p )
p[i] = a[i] - a[i - 1]
我们还知道:
a[i] = Σp[j](1 <= j <= i)
证明:
p[i] = a[i] - a[i - 1]
p[i] + p[i - 1] = a[i] - a[i - 1] + a[i - 1] - a[i - 2] = a[i] - a[i - 2]
...
p[i] + p[i - 1] + ... + p[1] = a[i] - a[i - 1] + a[i - 1] - a[i - 2] +... + a[1] - a[0] = a[i] - a[0]
又因为a[0] = 0
所以p[i] + p[i - 1] + … + p[1] + p[0] = a[i]
求单点即求差分序列的前缀和,又因为会进行修改,所以可以用树状数组维护前缀和
代码:
#include <cstdio>
#define LL long long
const int MAXN = 1e6 + 5;
int n, m;
int a[MAXN], d[MAXN];
LL BIT[MAXN];
int _Lowbit(int x) {return x & -x;}
void _Update(int, int);
LL _Sum(int);
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
d[i] = a[i] - a[i - 1];
_Update(i, d[i]);
}
// for(int i = 1; i <= n; i++) printf("%lld ", _Sum(i));
for(int i = 1; i <= m; i++) {
int flag;
scanf("%d", &flag);
if(flag == 1) {
int l, r, x;
scanf("%d %d %d", &l, &r, &x);
_Update(l, x);
_Update(r + 1, -x);
}
else {
int x;
scanf("%d", &x);
printf("%lld\n", _Sum(x));
}
}
return 0;
}
void _Update(int index, int x) {
for(int i = index; i <= n; i += _Lowbit(i))
BIT[i] += x;
return;
}
LL _Sum(int x) {
LL sum = 0;
for(int i = x; i > 0; i -= _Lowbit(i))
sum += BIT[i];
return sum;
}
3.区间修改,区间查询(♂难)
分析:这道题也是对一个区间进行修改,所以也同样想到差分序列,可是还要求差分序列前缀和的前缀和 (套娃),所以还要维护一个前缀和
求(1 ~ i)的前缀和(原数组),记作pre[i]
pre[i] = a[1] + a[2] + a[3] + ... + a[i - 1] + a[i]
= (p[1]) + (p[1] + p[2]) + (p[1] + p[2] + p[3]) + ... + (p[1] + p[2] + p[3] + ... + p[i])
= p[1] * i + p[2] * (i - 1) + p[3] * (i - 2) + ... + p[i] * 1
= i * (p[1] + p[2] + p[3] + ... p[i]) + p[1] * (1 - 1) + p[2] * (2 - 1) + p[3] * (3 - 1) + ... + p[i] * (i - 1)
BIT1维护p[1] + p[2] + p[3] + … p[i]的前缀和
BIT2维护p[1] * (1 - 1) + p[2] * (2 - 1) + p[3] * (3 - 1) + … + p[i] * (i - 1)的前缀和
若对i进行操作
则BIT1的增量是x,BIT2的增量是x * (i - 1)
证明:
欲证:该操作是对的~~/hj~~
设操作区间为[l, r]
若l <= i, r >= i
则pre[i + x] = pre[i] + x * i - x * (l - 1) = pre[i] + x * (i - l + 1)
正确
若l <= i, r <= i - 1
则pre[i + x] = pre[i] + x * r - x * (l - 1) = pre[i] + x * (r - l + 1)
正确
#include <cstdio>
#define LL long long
const int MAXN = 1e6 + 5;
int n, m;
int a[MAXN];
LL BIT1[MAXN], BIT2[MAXN];
void _Update (int, int);
LL _Sum (int);
int lowbit (int x) { return x & (-x); }
int main () {
scanf ("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf ("%d", &a[i]), _Update (i, a[i] - a[i - 1]);
for (int i = 1; i <= m; i++) {
int type; scanf ("%d", &type);
if (type == 1) {
int l, r, x; scanf ("%d %d %d", &l, &r, &x);
_Update (l, x);
_Update (r + 1, -x);
}
else {
int l, r; scanf ("%d %d", &l, &r);
printf ("%lld\n", _Sum (r) - _Sum (l - 1));
}
}
return 0;
}
void _Update (int index, int x) {
for (int i = index; i <= n; i += lowbit (i)) {
BIT1[i] += x;
BIT2[i] += (long long)(index - 1) * x;
}
}
LL _Sum (int index) {
LL cnt = 0;
for (int i = index; i > 0; i -= lowbit (i)) {
cnt += BIT1[i] * index;
cnt -= BIT2[i];
}
return cnt;
}