树状数组区间修改加区间查询

旧时模样 提交于 2019-12-31 11:14:08

其实之前在K大数查询中就已经用到了,只是一直没有说明
所以今天就来补个欠账。
感觉单点修改、区间查询和区间修改、单点查询没什么必要讲,这里就只讲区间修改、区间查询(其实也不难)。
设原数组第\(i\)位的值为\(a_i\)\(d_i=a_i-a_{i-1}\),则有(这里认为\(a_0=0\)):
\[a_x=\sum_{i=1}^x d_i\]
所以有:
\[\sum_{i=1}^x a_i= \sum_{i=1}^x \sum_{j=1}^i d_j =\sum_{i=1}^x(x-i+1)d_i\]
于是我们得到了:
\[\sum_{i=1}^x a_i=(x+1)\sum_{i=1}^x d_i-\sum_{i=1}^x d_i \times i\]
于是我们把原数组差分后维护两个树状数组,一个维护\(d_i\),一个维护\(d_i \times i\)
这样区间求和时可以在两个树状数组中查询得到前缀和,区间修改时就是差分数组的修改,每次修改两个点即可。
具体代码如下:

void add(int x,int y){for(int i=x;i<=n;i+=i&(-i)) c1[i]+=y,c2[i]+=(long long)x*y;}//给差分数组中的位置x加上y
long long sum(int x){//查询前x项的和
    long long ans(0);
    for(int i=x;i;i-=i&(-i)) ans+=(x+1)*c1[i]-c2[i];
    return ans;
}

其中\(c{1_i}\)维护的是\(d_i\)\(c{2_i}\)维护的是\(d_i\times i\)
比线段树好写多了是不?

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!