树状数组进阶
前置知识:
-
树状数组单点修改,区间修改。
-
差分。
下面我们考虑区间修改。
一开始我们维护的是部分前缀和,但是现在,区间修改显然不能用前缀和有关的做法。
单区间修改用差分就够了。但是这里有修改,考虑将 差分 和 树状数组 结合。
令 \(c\) 为 \(a\) 的差分,维护 \(a\) 的区间修改与区间和即可,这样 \(a\) 就是 \(c\) 的前缀和了。
那么区间修改只需要改 \(2\) 个点,单点询问只需要问前缀和。但是区间询问则怎么做?
显然,还是用前缀和相减,考虑前缀和。
那么考虑一个东西:
\[\sum_{i=1}^n a_i
\]
\[= \sum_{i=1}^n \sum_{j=1}^i c_j
\]
\[= \sum_{i=1}^n c_j (n-i+1)
\]
\[= n \times \sum_{i=1}^n c_j - \sum_{i=1}^n c_i (i-1)
\]
显然,前面一部分我们已经得到维护,后面我们维护 \(c_i (i-1)\) 即可,开两个树状数组维护。
const int N=1e5+1;
int c[N],b[N];
struct BIT {
inline int lowbit(int x) {return x&(-x);}
inline int sum(int x) {
int s=0; while(x>0)
s+=c[x]*x-b[x],x-=lowbit(x);
return s;
}
inline void update(int x,int k) {
while(x<=n) c[x]+=k,x+=lowbit(x);
}
} T;
简易的代码胜过复杂的说教。