这篇主要来讲一讲树状数组的区间修改
因为一个一个点改,毫无疑问耗时太长
所以,机智的人类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) (注意是7+1,不是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
是不是很神奇?
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(i) (i&-i)
typedef long long ll;
using namespace std;
const int N = 500005;
int n,m;
ll sum[N];
ll delta[N],deltai[N];
ll query(ll *p,int pos)
{
ll ans=0;
while(pos>0)
{
ans+=p[pos];
pos-=lowbit(pos);
}
return ans;
}
void updata(ll *p,int pos,int x)
{
while(pos<=n)
{
p[pos]+=x;
pos+=lowbit(pos);
}
}
int main()
{
int i,l,r,v;
ll hhh;
int s1,s2;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%lld",&hhh),sum[i]=sum[i-1]+hhh;
while(m--)
{
scanf("%lld",&hhh);
if(hhh==1) //1表示修改,l至r闭区间加上v
{
scanf("%d%d%d",&l,&r,&v);
updata(delta,l,v);
updata(delta,r+1,-v); //注意边界
updata(deltai,l,v*l);
updata(deltai,r+1,-v*(r+1));
}
else
{
scanf("%d%d",&l,&r); //l至r的和
s1=sum[l-1]+l*query(delta,l-1)-query(deltai,l-1); //注意边界,不理解就看上面的图
s2=sum[r]+(r+1)*query(delta,r)-query(deltai,r);
printf("%lld\n",s2-s1);
}
}
return 0;
}
感谢