树状数组 区间修改 全网最简单最清楚
来源:互联网 发布:linux重启命令init 编辑:程序博客网 时间:2024/06/04 20:08
愚蠢的我花了好久好久才看明白他的意思….
最近不是在弄树状数组嘛,然后这个区间修改,怎么也想不明白,今天看了一下午博客,总算弄懂了.
让我们开始.我会尽量使用常数而不是变量,为了让你完全清楚.
如果出现公式,都不难,如果你一时看不清,可以拿笔写一写,保证没有任何难度.
我们约定,a[i]代表数据本身,(为了和数组数组中的数据区别)
首先,我们要实现区间修改,那么我们就不能和以前一样,我们假设一个c数组,这里面c[i],代表着a[i]-a[i-1].
问题来到,为什么我们要构造c[i].
想一想,假如我要对a[l]+…+a[r]进行区间修改,怎么办?
首先,c[i],是a[i]数组的一个映射,也就是说,当我们使用a[i]来建立树状数组时,a[i]表现的是每个节点的数字本身,而我们的c[i],则是表现每个节点的数字之间的差.那么我们可以想象,假如a[l]~a[r],每个都加x,那么在用a[i]表示节点数字性质时,我们理所当然的就是每个都加x,但是我们现在用c[i]表示节点数字性质时,你会发现,除了c[l]会加x,c[r+1]会减x外,其他地方,都没有变化.这便是关键了.
结论,利用c[i]作为a[i]的映射,我们可以通过两次修改,达到原来的n次修改的效果.那么接下来,就是我们区间修改的具体实现了.
可以认为接下来的一切,并没有显著的逻辑,他只是就是这样而已.
当我们有了这个定义之后,显然的,a[2] = c[2]+c[1],a[3] = c[3]+c[2]+c[1].那么这时候,我们想要计算a[1]+a[2]+….+a[n],也就是
c1 + (c2+c1)+(c3+c2+c1)+(…)+(Cn+Cn-1+…+C1),对吧?
我们可以进行整合,将他变为
n*(c1+c2+c3+…+cn)-(0*c1+1*c2+2*c3+…+(n-1)*Cn).
为什么这里关键?你观察会发现,这是两个前缀和的形式,一个是c1+c2+..+cn,一个是(1-0)*c1+(2-1)*c2+…+(n-1)*Cn.
那么说道前缀和,我们树状数组要上场了!
我们不妨假设d[i]= (i-1)*c[i].
显然,我们维护一个c[i]数组对应的树状数组(注意他们两个不是一个东西),就可以很快的对c[i]进行求和,同时,建立c[i]的映射,d[i]的树状数组,也可以很快求出他的前缀和了.
具体看代码,这是一个模版题的代码.
codevs,区间修改区间求和
/* xzppp */#include <iostream>#include <vector>#include <cstdio>#include <string.h>#include <algorithm>#include <queue>#include <map>#include <string>#include <cmath>#include <bitset>#include <iomanip>using namespace std;#define FFF freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define MP make_pair#define PB push_backtypedef long long LL;typedef unsigned long long ULL;typedef pair<int,int > pii;typedef pair<double,double > pdd;typedef pair<double,int > pdi;const int MAXN = 200000+17;const int MAXM = 20;const int MAXV = 2*1e3+17;const int INF = 0x7fffffff;const int MOD = 1e9+7;LL bit[2][MAXN],n,a[MAXN];void add(int k,int p,LL x){ while(p<=n) { bit[k][p] += x; p += p&-p; }}LL sum(int k,int p){ LL res = 0; while(p>0) { res += bit[k][p]; p -= p&-p; } return res;}void additv(int from,int to,LL x){ add(0,from,x); add(0,to+1,-x); add(1,from,(from-1)*x); add(1,to+1,(to)*(-x));}LL sumitv(int from,int to){ LL res = 0; res += to*sum(0,to); res -= sum(1,to); res -= (from-1)*sum(0,from-1); res += sum(1,from-1); return res;}int main(){ #ifndef ONLINE_JUDGE FFF #endif int m; cin>>n; for (int i = 1; i <= n; ++i) { scanf("%lld",a+i); add(0,i,a[i]-a[i-1]); add(1,i,(i-1)*(a[i]-a[i-1])); } cin>>m; for (int i = 0; i < m; ++i) { LL cmd,a,b,c; scanf("%lld",&cmd); if(cmd==1) { scanf("%lld%lld%lld",&a,&b,&c); additv(a,b,c); } else { scanf("%lld%lld",&a,&b); printf("%lld\n",sumitv(a,b)); } } return 0;}
- 树状数组 区间修改 全网最简单最清楚
- 树状数组 区间修改
- 树状数组区间修改 neu1454
- 树状数组 区间修改查询
- 树状数组区间修改+查询
- poj3468(树状数组:区间修改 区间求和)
- 树状数组~poj3468~区间修改 区间查询
- 树状数组 --区间查询+区间修改
- 【codevs1082】【树状数组】 区间修改 区间查询
- 树状数组 区间修改区间求和总结
- 笔记 树状数组--区间查询+区间修改
- 树状数组实现 区间修改+区间查询
- 树状数组区间修改区间查询
- 树状数组 区间修改+区间查询
- 树状数组区间修改区间查询
- 树状数组 区间修改 区间查询
- 树状数组求区间最值(转载)
- 树状数组求区间最值
- 猜数字游戏--基于python
- 积累_知识_成长
- Servlet response中文乱码的解决
- 悦读---《万万没想到-用理工科思维理解世界》(2)
- HDU-5793 A Boring Question(打表找规律)
- 树状数组 区间修改 全网最简单最清楚
- object之toString方法深入剖析
- UVALive3126[Taxi Cab Scheme] DAG最小路径覆盖模型
- RabbitMQ简介
- vim插件之quickfix
- MVC在b/s系统下的应用图解
- centos 7.2关闭防火墙
- 安装node
- java 根据开始和结束日期得到之间所有日期集合