1 i x表示i位置+x, 2 i j表示i——j的所有数之和。
这是一道灰常简单的模拟题,首先将原数组改为树状数组,写好模板代码,碰到一个直接输处即可,注意输出i——j为闭区间,所以答案应为sum(i) - sum(j - 1),此处sum是前缀和。
#include
#include
using namespace std;
int n, a[1000005], s, l, r, ww;
long long c[1000005];
int lowbit(int x) {
return x & -x;
}
void update(int k, int shu) {//更新/建树函数
for(int i = k;i <= n; i+=lowbit(i)) {
c[i] += shu;
}
}
long long Sum(int zhong) {//求和
long long da = 0;
for(int i = zhong;i >= 1; i-=lowbit(i)) {
da += c[i];
}
return da;
}
int main() {
scanf("%d %d", &n, &s);
for(int i = 1;i <= n; i++) {
scanf("%d", &a[i]);
update(i, a[i]);//建树
}
for(int i = 1;i <= s; i++) {
scanf("%d", &ww);
if(ww == 1) {
scanf("%d %d", &l, &r);
update(l, r);//更新
}
else {
scanf("%d %d", &l, &r);
printf("%lld\n", Sum(r) - Sum(l - 1));//求区间和
}
}
return 0;
}
1 i j x表示(i, j)位置+x, 2 a b c d表示求左下角为(a, b)右上角为(c, d)的子矩阵和
这道题和一维的差不多,但是首先要将树状数组整体变为二维,你可以想象得到,就是子节点选列,列又再选行就可以求得,当然他和一维的最大区别就是要考虑重复的情况,这有点类似于二维前缀和。
就比如这样一个图,我们将和考虑成面积,最后要求到 V V V绿那么即有:
V 绿 色 V绿色 V绿色 = V 总 V总 V总 - ( V 蓝 V蓝 V蓝 + V 黄 V黄 V黄) - ( V 紫 V紫 V紫 + V 黄 V黄 V黄) + V 黄 V黄 V黄
所以最后输出我们只需找点即可。
#include
#include
using namespace std;
int n, m, flag, a, b, c, d;
long long BIT[10005][10005];
int lowbit(int x) {
return x & (-x);
}
void update(int kx, int ky, int x) {
for(int i = kx;i <= n; i += lowbit(i)) {
for(int j = ky;j <= m; j += lowbit(j)) {
BIT[i][j] += x;
}
}
}
long long Sum(int kx, int ky) {
long long sum = 0;
for(int i = kx;i > 0; i -= lowbit(i)) {
for(int j = ky;j > 0; j -= lowbit(j)) {
sum+=BIT[i][j];
}
}
return sum;
}
int main() {
scanf("%d %d", &n, &m);
while(scanf("%d", &flag) != EOF) {
if(flag == 1) {
scanf("%d %d %d", &a, &b, &c);
update(a, b, c);//修改
}
else {
scanf("%d %d %d %d", &a, &b, &c, &d);
printf("%lld\n", Sum(c, d) + Sum(a - 1, b - 1) - Sum(a - 1, d) - Sum(c, b - 1));//类似于二位前缀和的做法,先将大矩形的算出来,再将多算的矩形去掉
}
}
return 0;
}