树状数组的修改与查询总结
来源:互联网 发布:光子脱毛 知乎 编辑:程序博客网 时间:2024/06/06 09:31
研究了很长时间的树状数组,下面来做一个自己的总结。(如果以下见解有什么问题,欢迎指出)
树状数组是真的很有意思,根据我现在的理解,如果普普通通的不做任何东西,那么他的单点修改适用于区间查询,他的区间修改,适用于单点查询。
如果想要区间修改区间查询,就得费一点功夫了。
一 :单点修改,区间查询
这是树状数组一个比较常规的用法,不再详细解释。
int low_bit(int x){return x&(-x);}void add(int i,int c){ while(i<=n) //n是一共有多少点 {a[i]+=c;i+=low_bit(i); } }int q(int i){ int ans=0; while(i>0) {ans+=a[i];i-=low_bit(i); } return ans; } int main(){ add(i,c); // i是对那个点增加 c 是要增加的多少 //若查询 l--r 区间的和 ans=q(r)-q(l-1);}
二 :单点修改,单点查询
这问题挺傻逼的,这东西直接用数组就行了,没必要再用树状数组了。
三 :区间修改,单点查询
这也是树状数组一个比较常规的用法,不再详细解释
int low_bit(int x){ return x&(-x);}void add(int i,int c){ while(i<=n) //n是一共有多少点 { a[i]+=c; i+=low_bit(i); } }int q(int i){ int ans=0; while(i>0) { ans+=a[i]; i-=low_bit(i); } return ans;}int main(){add(l,c) add(r+1,-c)//对l--r区间加 c q(i) //查询i点的值 }
四 :区间修改,区间查询
这可能也是比较难理解的地方了。
但是认真仔细的看一看,还是很好理解的。
这也是,我看别人的博客,才知道的。
首先我们设原来的数组是a[i],a[i]里保存的是前i个元素的值总和。
然后设C1,C1代表的是a[i]-a[i-1],那么就是第i个元素的值;
我们假设sigma(r,i),表示r数组前i项的和。
网上有这样一个式子,其实这个式子的误导性很大。
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]) (式子①)
那么我们就维护一个数组c2[n],其中c2[i] = (i-1)*c[i]
式子①=n*sigma(c,n) - sigma(c2,n)
下面我们看一道题,来展示一下代码。
给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。
第一行一个正整数n,接下来n行n个整数,
再接下来一个正整数Q,每行表示操作的个数,
如果第一个数是1,后接3个正整数,
表示在区间[a,b]内每个数增加X,如果是2,
表示操作2询问区间[a,b]的和是多少。
pascal选手请不要使用readln读入
对于每个询问输出一行一个答案
3
1
2
3
2
1 2 3 2
2 2 3
9
数据范围
1<=n<=200000
1<=q<=200000
题目来源:点击打开链接
#include <cstdio> #define lowbit(x) (x&-x) #define ll long long #define maxn 200010 using namespace std; ll n, q, c1[maxn], c2[maxn], num[maxn]; void add(ll *r, ll pos, ll v) {for(;pos<=n;pos+=lowbit(pos))r[pos]+=v;} ll sigma(ll *r, ll pos) { ll ans; for(ans=0;pos;pos-=lowbit(pos))ans+=r[pos]; return ans; } int main() { ll i, j, type, a, b, v, sum1, sum2; scanf("%lld",&n); for(i=1;i<=n;i++) { scanf("%lld",num+i); add(c1,i,num[i]-num[i-1]); add(c2,i,(i-1)*(num[i]-num[i-1])); } scanf("%lld",&q); while(q--) { scanf("%lld",&type); if(type==1) { scanf("%lld%lld%lld",&a,&b,&v); add(c1,a,v);add(c1,b+1,-v); add(c2,a,v*(a-1));add(c2,b+1,-v*b); } if(type==2) { scanf("%lld%lld",&a,&b); sum1=(a-1)*sigma(c1,a-1)-sigma(c2,a-1); sum2=b*sigma(c1,b)-sigma(c2,b); printf("%lld\n",sum2-sum1); } } return 0; }
- 树状数组的修改与查询总结
- 【小结】树状数组的区间修改与区间查询
- 树状数组的区间修改与区间查询
- 数据结构----树状数组----二维区间的修改与查询
- 树状数组的区间修改,单点查询
- 树状数组 区间修改查询
- 树状数组区间修改+查询
- 可以区间修改区间查询的树状数组云云
- 树状数组的应用(区间修改+区间查询)
- 树状数组的区间修改和区间查询模板
- 树状数组的应用(区间修改,区间查询,多维树状数组)
- 【树状数组】区间修改&点查询
- 【树状数组】点修改&区间查询
- 树状数组~poj3468~区间修改 区间查询
- 【树状数组】段修改,点查询
- hdu1556 树状数组 区间修改,点查询
- 树状数组 --区间查询+区间修改
- 【codevs1080】【树状数组】 单点修改 区间查询
- 我是如何学习PHP整个体系的
- Angular2之组件交互和数据绑定
- 逆向实战之去广告的简单练习
- css实现高亮边框
- Jedis针对redis的操作
- 树状数组的修改与查询总结
- 使用优先队列在iOS中实现消息排序
- Regex—匹配特定字符后的一个字符
- mysql数据库关联查询
- IDEA JVM 参数设置
- Qt中用qSort()快速排序例程
- php函数set_include_path()用法详解
- a标签
- javascript 使用FormData实现图片/文件异步上传