【小结】树状数组的区间修改与区间查询
来源:互联网 发布:单片机怎么处理at指令 编辑:程序博客网 时间:2024/06/05 19:26
第一次听到树状数组是zsl来讲课QAQ 然后当时他给我们绕了很久 = = 嗯没懂…………结果后来发现这东西实际上是个简单又好用的玩意QAQ
不知道以后的题还会不会用了 因为感觉好像树状数组的题一般都比较简单orz。。
[ 1 ] 树状数组的本职是单点修改+区间查询 维护前缀和 每次修改向上传数据 然后查询区间的时候也是从下往上加值 函数很好写……
修改:
void update(int i, int x){ while(i <= N){ sum[i] += x; i += lowbit(i); }}
查询前缀和:
int Query(int i){ int temp = 0; while(x > 0){ temp += sum[i]; i -= lowbit(i); } return temp;}
[ 2 ] 鉴于树状数组的空间复杂度和时间复杂度都比线段树小 而且代码也短 所以就有大神用强大的脑洞YY出了区间修改+单点查询的树状数组
= =我的想法是保存原始数列a数组 然后引入delta数组(差分数组) 查询的时候求delta数组的前缀和 再加上原始的a数组就可以了 网上的资料似乎和我的方法不太一样但是……应该也差不多吧……按我的方法的话 代码和上面也差不多 把sum改成delta就行了
[ 3 ] 上面都不是重点……重点是树状数组的区间修改+区间查询 这个很好玩 其实也挺简单
首先依旧是引入delta数组 delta[i]表示区间 [i, n] 的共同增量 于是修改区间 [l, r] 时修改 delta[l] 和 delta[r + 1] 即可(就是差分的思路)
查询的时候是查询区间 [l, r] 的和 即sum[r] - sum[l - 1] 所以现在的问题是求sum[i]
sum[i] = a[1]+...+a[i] + delta[1]*i + delta[2]*(i - 1) + delta[3]*(i - 2)+...+delta[i]*1 // a[i]为原始数组 = sigma( a[x] ) + sigma( delta[x] * (i + 1 - x) ) = sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )
其中 sigma( a[x] ) 是可以预处理出来的 于是只需要维护 delta[x] 与 delta[x] * x 的前缀和(作为两个树状数组就可以了)
为了试验这个方法我专门去找了之前写线段树挂了好久的例题 = = codevs1082 线段树练习3
然后交树状数组的代码是 324ms 内存5M过了 线段树是1027ms 13M 如果去掉读入优化的话代码会更短。
/*作者:Airy题目:p1082 线段树练习 3*/#include <cstdio>#include <iostream>#define lowbit(i) (i & (-i))using namespace std;int readint(){int sign = 1, n = 0; char c = getchar();while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar(); }while(c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }return sign*n;}const int Nmax = 200100;int N, Q;long long delta[Nmax]; // delta的前缀和 long long deltai[Nmax]; // delta * i的前缀和 long long sum[Nmax]; // 原始前缀和long long Query(long long *array, int pos){long long temp = 0ll;while(pos > 0){temp += array[pos];pos -= lowbit(pos);}return temp;}void Update(long long *array, int pos, int x){while(pos <= N){array[pos] += x;pos += lowbit(pos);}}int main(){N = readint();for(int i = 1; i <= N; ++i){int x = readint();sum[i] = sum[i - 1] + x;}Q = readint();while(Q--){int sign = readint();if(sign == 1) // 修改:把[l, r]区间均加上x {int l = readint(), r = readint(), x = readint();Update(delta, l, x);Update(delta, r+1, -x);Update(deltai, l, x * l);Update(deltai, r+1, -x * (r+1));} else // 查询:[l, r]区间和 {int l = readint(), r = readint(); long long suml = sum[l - 1] + l * Query(delta, l - 1) - Query(deltai, l - 1);long long sumr = sum[r] + (r + 1) * Query(delta, r) - Query(deltai, r);printf("%lld\n", sumr - suml);}}return 0;}
大概就是这样了。
1 0
- 【小结】树状数组的区间修改与区间查询
- 树状数组的区间修改与区间查询
- 数据结构----树状数组----二维区间的修改与查询
- 树状数组的区间修改,单点查询
- 树状数组~poj3468~区间修改 区间查询
- 树状数组 --区间查询+区间修改
- 【codevs1082】【树状数组】 区间修改 区间查询
- 笔记 树状数组--区间查询+区间修改
- 树状数组实现 区间修改+区间查询
- 树状数组区间修改区间查询
- 树状数组 区间修改+区间查询
- 树状数组区间修改区间查询
- 树状数组 区间修改 区间查询
- 树状数组 区间修改查询
- 树状数组区间修改+查询
- 可以区间修改区间查询的树状数组云云
- 树状数组的应用(区间修改+区间查询)
- 树状数组的区间修改和区间查询模板
- C语言中的数据类型
- Android 开发学习小结(三)
- SCALA学习笔记(一)
- Linux 命令23-Linux目录结构
- MyEclipse中web项目修改部署路径
- 【小结】树状数组的区间修改与区间查询
- work_link
- 顺序存储结构
- Android 开发学习小结(四)
- 变量的理解
- CRC与MD5理解
- VS2010中dumpbin工具的使用
- Android 开发学习小结(五)
- 做电商一开始就做品牌,结果死了