首页 > 代码库 > 树状数组 小白篇(2)暨区间修改

树状数组 小白篇(2)暨区间修改

这篇主要来讲一讲树状数组的区间修改

因为一个一个点改,毫无疑问耗时太长

所以,机智的人类YY出了用差分来表示数组

为了便于理解,简单一点数组{an}:a[1]=0, a[2]=0, a[3]=0, a[4]=0, a[5]=0, a[6]=0 ,a[7]=0, a[8]=0, a[9]=0

用差分思想,delta[x]表示a[x]-a[x-1]

显然,一开始delta[]=0

我们先计算出前n项和{sn}来

然后别眨眼,下面就是见证奇迹的时刻!

 

 

有个分界线显得正式一点


 

我们要把a[3]到a[6]整段提高3个单位长度,就让delta[3]+=3, delta[7]-=3

想象成阶梯,一端抬起,另一端就压下去。(自行脑补)

那么现在的a[x]+=delta[1]+delta[2]+……+delta[x-1]+delta[x]

我现在要得到前7项的和,s[7]+=每一项应该加的差分

          暨s[7]+=(delta[1])+(delta[1]+delta[2])+(delta[1])+delta[2]+delta[3])+……+(delta[1]+delta[2]+delta[3]+delta[4]+delta[5]+delta[6]+delta[7])

我还是画个图吧(为了方便说明只画差分的)

技术分享

显然搬过砖的都知道,这个砖不好搬,因为它不方

那我们就把它变方来

技术分享

(为什么那么丑,因为我不会画画以及懒)

额妹子!现在就好表示这堆砖了!!!!!!!!!

(7+1)(∑delta【1~7】)-(delta【1】*1+delta【2】*2+……+delta【7】*7)

后面的delta【n】*n很难看是不是?

那就表示成deltai【】

定义deltai【i】=delta【i】*i

显然因为要大量求和,所以我们把deltai和delta维护成树状数组

那么

1 // 修改:把[l, r]区间均加上x     
2 Update(delta, l, x);       
3 Update(delta, r+1, -x);  
4 Update(deltai, l, x * l);  
5 Update(deltai, r+1, -x * (r+1)); 
6 //updata相当于上一篇的add
// 查询:[l, r]区间和     
long long suml = s[l - 1] + l * Query(delta, l - 1) - Query(deltai, l - 1);  
long long sumr = s[r] + (r + 1) * Query(delta, r) - Query(deltai, r);  
ans=sumr - suml;  
//query相当于上一篇的sum

是不是很神奇?

感谢

“每天心塞一点点”的博客(我喜欢这个名字)

参考博文地址

树状数组 小白篇(2)暨区间修改