关于树状数组区间修改和查询详解
来源:互联网 发布:万网单域名控制台登录 编辑:程序博客网 时间:2024/06/16 15:59
原版介绍
这里我想再加上自己的理解,解释一下。
现在我们需要的是把某个区间的值修改,然后查询
我们设原数组为
a[1] a[2] …. a[n]
我们添加一个c1数组 来记录此项与前一项的差值 即
c1[i] = a[i] - a[i-1]
再添加上c2数组,根据公式c1与c2的关系(下面会说到)
c2[i] = (i-1)*(a[i] - a[i-1])
下面是推导过程:
a[1]+a[2]+…+a[n]
= (c[1]) + (c[1]+c[2]) + … + (c[1]+c[2]+…+c[n])
= n * c[1] + (n-1) * c[2] +… +c[n]
= n * (c[1]+c[2]+…+c[n]) - (0 * c[1]+1* c[2]+…+(n-1) * c[n]) ①
这就是三者之间关系,根据规律,提取公式
0 * c[1] + 1* c[2] + … + (n-1) * c[n] →用c2记录 → c2[i] = (i-1)*c[i]
根据①式,我们得出
原式 = n*sigma(c1, n) - sigma(c2, n) //sigma(c1, n)代表c1数组的前n项和
这里才能体现出c2的作用 → 帮助更好的计算
这样前提工作做好了
首先第一个要求是把区间 [left,right] 内所有的数加上 x
这里我们写一个和单个修改类似的函数add
void add(ll *a, ll pos, ll x) { while( pos <= n ) { a[pos] += x; pos += lowbit(pos); }}
通过这个函数,其实是把从 left 开始以后的数全都加上了 x 所以需要减掉 right 以后的数
add(c1, left, x); add(c1, right+1, -x);
由于c1数组变化了,所以c2数组也要变化
add(c2, left, (left-1)*x); //更新标记数组 add(c2, right+1, -right*x); //把多余的去掉
同样还是需要减去多加的数字
这样的话就已经完成了修改,只需要把sigma函数写出来输出就可以了
这只是其中一种做法
下面是一个模板例题
例题:线段树练习
代码如下:
#include<cstdio>#include<iostream>#define lowbit(x) x&(-x)#define maxn 200010#define ll long longusing namespace std;ll n; ll a[maxn];//原数组 ll c1[maxn];//差值数组 ll c2[maxn];//根据差值数组根据关系推得的一组数据 起名为标记数组 ll sigma(ll *a, ll pos) { ll sum = 0; while(pos > 0) { sum += a[pos]; pos -= lowbit(pos); } return sum;}void add(ll *a, ll pos, ll x) { while( pos <= n ) { a[pos] += x; pos += lowbit(pos); }}int main() { cin >> n; for(ll i = 1; i <= n; i++) { cin >> a[i]; add(c1, i, a[i] - a[i-1]); //把该项与前一项的差值记录下来 add(c2, i, (i-1)*(a[i] - a[i-1])); //根据公式来更新标记数组 } ll t; cin >> t; while( t-- ) { ll index, left, right, x; cin >> index; if(index == 1) { cin >> left >> right >> x; add(c1, left, x); //更新数组 add(c1, right+1, -x); //由于前面更新过,把多余的减去 add(c2, left, (left-1)*x); //更新标记数组 add(c2, right+1, -right*x); //把多余的去掉 } //右边界都要去掉,因为到该项结束,但是不能修改 if(index == 2) { cin >> left >> right; ll sum1 = (left-1)*sigma(c1, (left-1)) - sigma(c2, (left-1));//公式 ll sum2 = right*sigma(c1, right) - sigma(c2, right); cout << sum2 - sum1 << endl; } } return 0;}
- 关于树状数组区间修改和查询详解
- 树状数组的区间修改和区间查询模板
- 树状数组 区间修改查询
- 树状数组区间修改+查询
- 树状数组~poj3468~区间修改 区间查询
- 树状数组 --区间查询+区间修改
- 【codevs1082】【树状数组】 区间修改 区间查询
- 笔记 树状数组--区间查询+区间修改
- 树状数组实现 区间修改+区间查询
- 树状数组区间修改区间查询
- 树状数组 区间修改+区间查询
- 树状数组区间修改区间查询
- 树状数组 区间修改 区间查询
- 【树状数组】区间修改&点查询
- 【树状数组】点修改&区间查询
- 树状数组的区间修改,单点查询
- hdu1556 树状数组 区间修改,点查询
- 【codevs1080】【树状数组】 单点修改 区间查询
- 222.map4-百度地图添加覆盖物
- NYOJ:50-爱摘苹果的小明
- 矩阵乘法编写,从文件输入输出
- pandas value_couts遇到的问题
- PL/SQL面向过程语言
- 关于树状数组区间修改和查询详解
- 迷失的几个月
- Java开发IDE工具Eclipse使用笔记
- 破解vs2008
- framework学习之路
- 关于H5端大图上传的问题
- 在多线程中注入spring对象
- 链表面试题(二):冒泡排序、合并两个有序链表、查找中间节点、查找倒数K个节点
- 数据库基础知识小结