树状数组区间修改和区间求和

Posted cyheimu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组区间修改和区间求和相关的知识,希望对你有一定的参考价值。

最一般树状数组能做到的操作是单点修改,区间求和,都是log(n)级别的。原理就是用树状数组维护a[i]的部分和。

想要做到修改区间,求单点值也很简单,用树状数组维护a[i]的差分数组d[i]的部分和既可。

 

那么,如何同时做到区间求和,区间修改呢?

 

有人可能会说了,如果是区间求和区间修改的话,直接写线段树不就好了吗?

但是,从代码长度来看(dalao请无视),显然使用树状数组在考场上出错率会小一些,而且比较爽QWQ

回归正题。我们知道,想要达到log(n)级别的区间修改需要修改d[i],那么在修改d[i]的情况下想要区间求和,我们就应该维护这个:

 

找出d[i]与a[i]的前缀和的关系,并用树状数组维护这个关系。

 

那么如何找关系呢?这里需要一点点数学证明: 

 

我们设sum(i)=a[1]+a[2]+a[3]+······+a[i],

则可知

 sum(i)=(d[1])+(d[1]+d[2])+(d[1]+d[2]+d[3])+······+(d[1]+d[2]+d[3]+······+d[i]),

所以

sum(i)=i*d[1]+(i-1)*d[2]+(i-2)*d[3]+······+1*d[i],

所以

sum(i)=∑(j从1到i)(i-j+1)d[j],

最后一步化简后,我们得到这样一个式子: 

 

sum(i)=(i+1)∑(j从1到i)d[j]-∑(j从1到i)j*d[j]

 

即我们需要用树状数组分别维护d[i]的和和i*d[i]的和既可。 

下面上代码:

 1#include <iostream>
2#include <cstdio>
3#include <cstdlib>
4#include <algorithm>
5using namespace std;
6
7long long n,m;
8long long c1[100010],c2[100010];
9
10void update(long long x,long long k)
11

12    long long i=x;
13    while(x<=n)
14    
15        c1[x]+=k;
16        c2[x]+=i*k;
17        x+=x&-x;
18    
19    return;
20
21
22long long sum(long long x)
23

24    long long ans=0;
25    long long i=x;
26
27    while(x>0)
28    
29        ans+=c1[x]*(i+1);
30        ans-=c2[x];
31        x-=x&-x;
32    
33    return ans;
34
35
36int main()
37

38    long long ord,x,y,k;
39    long long a,b=0;
40
41    scanf("%lld%lld",&n,&m);
42    for(long long i=1;i<=n;i++)
43    
44        scanf("%lld",&a);
45        update(i,a-b);
46        b=a;
47    
48    for(long long i=1;i<=m;i++)
49    
50        scanf("%lld",&ord);
51        if(ord-1)
52        
53            scanf("%lld%lld",&x,&y);
54            printf("%lld\n",sum(y)-sum(x-1));
55        
56        else
57        
58            scanf("%lld%lld%lld",&x,&y,&k);
59            update(x,k);
60            update(y+1,-k);
61        
62    
63    return 0;
64

以上是关于树状数组区间修改和区间求和的主要内容,如果未能解决你的问题,请参考以下文章

资瓷区间修改+区间求和的树状数组(一维/二维)

树状数组区间更新

树状数组2 - 区间加 单点求和

如何利用树状数组修改一个区间?

树状数组区间加区间求和

树状数组 1/30