0
点赞
收藏
分享

微信扫一扫

LOJ #135 && 树状数组一维二维各种操作的分析


题目链接:​​传送门​​

复习一下二维树状数组
省的写一次忘一次遇到题就去看板子

一维的区间修改+单点查询

对于一维的区间修改和单点查询
我们用的方法是差分
差分数组的前缀和等于原数组
所以如果对区间加上
那就在差分数组的
比如原数组为
它的差分数组就是
特别地,可以定义
它的差分数组为
可以自行尝试一下,这个数组的前缀和就是上面的原数组
如果对这个区间加了
照上面所说的方法
对差分数组在
那么差分数组变成了
对这个数组做前缀和就是
就是上面的数组在区间加了之后的效果

二维的区间修改+单点查询

二维的和一维类似,也是差分
只是差分数组的定义是
为什么是这样?因为要保证它的前缀和是原数组
二维前缀和:
在区间修改的时候,假设修改矩形的两个端点为,区间加
那么要在差分数组的
这样修改就不会影响其他元素的值,而且对这个矩形加了,可以自己画图理解一下

一维的区间修改+区间查询

相比上面的,这里变成了区间查询
假设我们要查询的区间为
那么我们可以变成查询区间的值相减
所以只需要考虑如何查询区间的值
查询的区间和,即为
由于有区间修改,所以差分数组还是要用的
用上差分数组后就变成了
然后考虑每个的贡献,想一下前几个就能知道:
被用了次,被用了次……被用了
上面的式子就可以化成
把括号拆开,就是
所以我们的树状数组需要维护
打的好累x

二维的区间修改+区间查询

又在二维的情况上添加了区间查询
还是像上面一样,的区间和为
加上差分数组后,区间和变成
继续考虑的贡献
加了次,加了次……出现了
式子简化为
再把式子展开之后就可以看出(这里就不写了,乘开就可以),我们需要维护:

x打的好累
给最后这种类型的代码,上面那些都可以用这个做
如果出题人不卡空间,​​​例题​​

#include <bits/stdc++.h>
#define

using namespace std;
typedef long long ll;
ll t1[B][B], t2[B][B], t3[B][B], t4[B][B], delta;
int n, m, a, b, c, d, opt;
int lowbit(int x) {return x & -x;}
void add(int x, int y, ll ad) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j)) {
t1[i][j] += ad;
t2[i][j] += ad * x;
t3[i][j] += ad * y;
t4[i][j] += ad * x * y;
}
}
void addval() {
add(a, b, delta); add(a, d + 1, -delta);
add(c + 1, b, -delta); add(c + 1, d + 1, delta);
}
ll ask(int x, int y, ll ans = 0) {
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ans += (x + 1) * (y + 1) * t1[i][j] - (y + 1) * t2[i][j] - (x + 1) * t3[i][j] + t4[i][j];
return ans;
}

int main(int argc, char const *argv[]) {
scanf("%d%d", &n, &m);
while (scanf("%d", &opt) != EOF) {
scanf("%d%d%d%d", &a, &b, &c, &d);
if (opt == 1) scanf("%lld", &delta), addval();
else printf("%lld\n", ask(c, d) - ask(c, b - 1) - ask(a - 1, d) + ask(a - 1, b - 1));
}
return 0;
}


举报

相关推荐

0 条评论