树状数组区间修改+单点查询详解

树状数组区间修改+单点查询详解

   阅读前需掌握的前置知识:树状数组的基本概念和它的单点修改+区间查询操作。

    众所周知,树状数组这一结构可以很好的解决动态前缀和的问题。单点修改+区间查询是它最常见的套路。但树状数组的强大功能可不止这一个,今天就为大家介绍它的区间修改+单点查询功能。不得不佩服,为树状数组赋予这一功能的人脑洞真的是太大。我们想想,怎样才能把单点查询转换为前缀和的问题呢?

    这里就要运用到一个妙不可言的思想:差分。它大概说的就是算出两项之差,然后进行处理。

    我们把原数组命名成sum,然后引入delta差分数组,令delta[i]=sum[i]-sum[i-1]。注意,在这里默认sum[0]=0。

    先陈述一个事实:

    

    为什么呢?很简单,我们把delta数组之和这个式子转换一下:

     delta[1]+delta[2]+...+delta[i-1]+delta[i]

    =sum[1]-sum[0]+sum[2]-sum[1]+...+sum[i-1]-sum[i-2]+sum[i]-sum[i-1]

    =sum[0]+sum[i]

    =sum[i]

    是不是有一种恍然大悟的感觉?~~~

    心细的同学可能已经注意到了,由delta数组维护sum数组的时候,不就是一个前缀和吗!!!我们就可以运用树状数组来维护了!具体来说,我们以delta数组为树状数组来维护,每次更新差分序列,当要查询某个数时,直接前缀和累加就好了。

    这里还有一个重点,就是如何add给区间加数。这里也是一个最巧妙的地方。

    我们假设现在有一个数列:1 5 3 8 9。如果我们把[2,4]这个区间统一加上3,那么原数列变为:1 8 6 11 9

    现在我们对比来看原数列和现数列的差分序列:原:1 4 -2 5 1 现:1 7 -2 5 -2

    我们可以很清楚的看到,除了delta[2]和delta[5],其他差分数都没有发生变化。如果你再多列举一些例子,就会发现,若在[l,r]这个区间里统一加上x,那么差分序列的改变为:delta[l]+=x,delta[r+1]-=x。那么这是为什么呢?很简单,如果两个相邻的元素同时加上一个数或者同时不改变,那么他们的差也不会改变。对比整个数列中两两相邻的情况,发现只有这两组数,没有进行统一改变,那么差值自然改变。至于一个是+=一个是-=,就不用说了吧,想一想就知道为什么了~~~

    请仔细咀嚼一下这句精妙的话:差分是前缀和的逆运算

    大体就是这样子啦!最后总结一下区间修改+单点查询的要点!

    1:注意是维护差分数组,一习惯就可能打成普通树状数组。

    2.add的时候以单点修改+区间查询为基本框架,只是以差分为思想,每次进行add(l,x)和add(r+1,-x)。

    3.查询第x个位置的数的时候,直接求前x个位置的前缀和就好了。

    下面给出标准的区间修改+单点查询的代码:

 

 1 #include<bits/stdc++.h>
 2 #define MX 100005
 3 using namespace std;
 4 int n,ans[MX],tree[MX];int lowbit(int x){return x&-x;}
 5 void add(int x,int q){while(x<=n){tree[x]+=q;x+=lowbit(x);}}
 6 int query(int x){
 7     int tot=0;while(x>=1){tot+=tree[x];x-=lowbit(x);}return tot;
 8 }
 9 int main(){
10     int m,k,last=0;cin>>n>>m>>k;
11     for(int i=1;i<=n;i++){int q;cin>>q;add(i,q-last);last=q;}
12     for(int i=1;i<=m;i++){int le,ri,q;cin>>le>>ri>>q;add(le,q);add(ri+1,-q);}
13     for(int i=1;i<=k;i++){int q;cin>>q;ans[i]=query(q);}
14     for(int i=1;i<=k;i++)cout<<ans[i]<<' ';
15     return 0;
16 }
View Code

   

    这篇博客就到这里啦~~喜欢的请点赞哦~~

 

 

posted @ 2020-02-26 11:28  soul_maker  阅读(910)  评论(0编辑  收藏  举报