利用差分实现的树状数组区间修改 区间求和
2017-08-01 15:17
323 查看
最开始和很不敢相信竟然树状数组还可以区间修改,既然常数这么小,而且好写易调的树状数组可以写区间修改了,那岂不美滋滋?
所以我在网上查了查做法,竟然学会了???
Orz http://blog.csdn.net/qq_21841245/article/details/43956633
这篇博客给了我很大帮助
然后我们可以这样思考,如果现在是区间修改,单点查询,那么我们是不是可以差分一下,在区间的开始和结束进行差分标记,然后用树状数组维护差分数组的前缀和即可,然后询问的时候只需要询问到到这个点的差分数组的前缀和再加上这个点的值就可以吧
那么如果是区间修改区间查询呢?我们仍然维护前缀和,也是差分数组的前缀和,不过维护的方式有一些变化,我们进行如下的公式推导
sum[i]=∑j=1ia[j]+delta[1]∗i+delta[2]∗(i−1)+...+delta[i]∗1
=∑j=1ia[j]+∑j=1idelta[j]∗(i−j+1)
=∑j=1ia[j]+∑j=1idelta[j]−∑j=1idelta[j]∗j
所以我们只需要维护后面的两个式子就行了,分别用两个树状数组维护delta[x]的前缀和和delta[x]*x的前缀和,而前面的那个式子我们可以预处理出来
所以我也写了那位博主的那道题,果然奇快233
所以我在网上查了查做法,竟然学会了???
Orz http://blog.csdn.net/qq_21841245/article/details/43956633
这篇博客给了我很大帮助
然后我们可以这样思考,如果现在是区间修改,单点查询,那么我们是不是可以差分一下,在区间的开始和结束进行差分标记,然后用树状数组维护差分数组的前缀和即可,然后询问的时候只需要询问到到这个点的差分数组的前缀和再加上这个点的值就可以吧
那么如果是区间修改区间查询呢?我们仍然维护前缀和,也是差分数组的前缀和,不过维护的方式有一些变化,我们进行如下的公式推导
sum[i]=∑j=1ia[j]+delta[1]∗i+delta[2]∗(i−1)+...+delta[i]∗1
=∑j=1ia[j]+∑j=1idelta[j]∗(i−j+1)
=∑j=1ia[j]+∑j=1idelta[j]−∑j=1idelta[j]∗j
所以我们只需要维护后面的两个式子就行了,分别用两个树状数组维护delta[x]的前缀和和delta[x]*x的前缀和,而前面的那个式子我们可以预处理出来
所以我也写了那位博主的那道题,果然奇快233
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<queue> #include<set> const int MAXN=200000*4; using namespace std; int lowbit(int x){return x&(-x);} int n,Q,opt,x,y; long long A[MAXN],C[MAXN],sum[MAXN],z; void modifyA(int x,int val){ while(x<=n){ A[x]+=val; x+=lowbit(x); } } void modifyC(int x,long long val){ while(x<=n){ C[x]+=val; x+=lowbit(x); } } void update(int from,int to,long long val){ modifyA(from,val); modifyA(to+1,-val); modifyC(from,val*from); modifyC(to+1,-val*(to+1)); } long long queryA(int loc){ long long ans=0; while(loc){ ans+=A[loc]; loc-=lowbit(loc); } return ans; } long long queryC(int loc){ long long ans=0; while(loc){ ans+=C[loc]; loc-=lowbit(loc); } return ans; } long long query(int loc){ return sum[loc]+(loc+1)*queryA(loc)-queryC(loc); } long long query(int from,int to){ return query(to)-query(from-1); } int main(){ scanf("%d",&n); for(register int i=1;i<=n;i++)scanf("%d",&sum[i]),sum[i]+=sum[i-1]; scanf("%d",&Q); while(Q--){ scanf("%d%d%d",&opt,&x,&y); if(opt==1){ scanf("%lld",&z); update(x,y,z); }else{ printf("%lld\n",query(x,y)); } } return 0; }
相关文章推荐
- 【模板】树状数组 区间修改,区间求和 (模板题:洛谷P3372线段树1)
- 【树状数组】【单点修改区间求和】【区间修改单点查询】【单点修改区间最大值查询】
- 树状数组一、二维区间修改与求和
- poj1195(二维树状数组,点修改,区间求和)
- 树状数组( 单点修改/区间修改+区间求和+一维/二维)
- 树状数组模版(单点修改区间求和)(区间修改单点求值)(区间修改区间求和)
- 【模板】树状数组 单点修改,区间求和 (模板题:洛谷P3374树状数组1)
- 树状数组关于区间修改区间求和的问题
- 树状数组实现 区间修改+区间查询
- 【模板】树状数组 区间修改,区间求和 (模板题:洛谷P3368树状数组2)
- 树状数组的区间修改求和
- 树状数组 区间修改 差分
- HDU 1166 敌兵布阵(树状数组 or 线段树 单点修改 区间求和)
- poj3468(树状数组:区间修改 区间求和)
- hdu1166(树状数组,点修改,区间求和)
- 详解树状数组 区间修改求和
- hdoj 3874 —— 树状数组单点修改+区间求和
- 树状数组 区间修改区间求和总结
- 树状数组 --区间查询+区间修改
- 树状数组总结——详解(单点/区间查询, 单点/区间修改, 逆序对)