码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2019-06-23 15:59:09      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:ons   lib   otto   cpp   一个   sans   树状   microsoft   style   

最一般树状数组能做到的操作是单点修改,区间求和,都是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}

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

标签:ons   lib   otto   cpp   一个   sans   树状   microsoft   style   

原文地址:https://www.cnblogs.com/CYHeimu/p/11058205.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!