前言
相信大家都会树状数组的"单点修改,区间查询"或者"区间修改,单点查询",博主就不细讲了。
但是博主今天发现了一个神奇的算法(博主太菜),它可以使用树状数组维护"区间修改,区间查询"。
单点修改,区间查询
就是一个优化过的前缀和,使查询和修改协调为(Theta(log_2n))
代码
namespace FenTree{
#define lowbit(x) (x&-x)
#define MAXN 100005
int BIT[MAXN];
int query(int i){
int res = 0;
for ( ; i; i -= lowbit(i)) res += BIT[i]; return res;
}
void add(int i, int val){
for ( ; i <= n; i += lowbit(i)) BIT[i] += val;
}
#undef MAXN
#undef lowbit
};
区间修改,单点查询
将上面的树状数组进行差分,就珂以了
区间修改,区间查询
算法详解
设原数组(a)从下标一开始,长度为(n),(a_i-a_{i-1})记为(delta_i),我们规定(a_0=0)
那么
[a_i=sum_{j=1}^i{delta}_i
]
上式求和时两两抵消,易证。
所以,若(xin[1,n])
[sum_{i=1}^xa_i=sum_{i=1}^xsum_{j=1}^i{delta}_j=sum_{i=1}^x(x-i+1) imes{delta}_i
]
于是
[sum_{i=1}^xa_i=(x+1)sum_{i=1}^x{delta}_i-sum_{i=1}^x{delta}_i imes i
]
最后我们愉快的差分维护两个树状数组,
一个维护(d_i),另一个维护(d_i imes i)
代码
namespace FenWick{
#define lowbit(x) (x&(-x))
#define ll long long
#define MAXN 1000005
int n;
ll d1[MAXN] , d2[MAXN];
void modifySuffix(int x, ll val){
for (int i = x; i <= n; i += lowbit(i))
d1[i] += val, d2[i] += val * x;
}
inline void modify(int x, int y, ll val){
modifySuffix(x, val), modifySuffix(y + 1, -val);
}
ll queryPrefix(int x){
ll res = 0;
for (int i = x; i; i -= lowbit(i))
res += (x + 1) * d1[i] - d2[i];
return res;
}
inline ll query(int x, int y){
return (queryPrefix(y) - queryPrefix(x - 1));
}
};
练习
#include <cstdio>
namespace FenWick{
#define lowbit(x) (x&(-x))
#define ll long long
#define MAXN 1000005
int n;
ll d1[MAXN] , d2[MAXN];
void modifySuffix(int x, ll val){
for (int i = x; i <= n; i += lowbit(i))
d1[i] += val, d2[i] += val * x;
}
inline void modify(int x, int y, ll val){
modifySuffix(x, val), modifySuffix(y + 1, -val);
}
ll queryPrefix(int x){
ll res = 0;
for (int i = x; i; i -= lowbit(i))
res += (x + 1) * d1[i] - d2[i];
return res;
}
inline ll query(int x, int y){
return (queryPrefix(y) - queryPrefix(x - 1));
}
};
using namespace FenWick;
ll read(){
ll x = 0; int zf = 1; char ch = ' ';
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}
int main(){
n = read(); int q = read();
for (int i = 1; i <= n; ++i)
modify(i, i, read());
while (q--){
int op = read(), l = read(), r = read(), x;
switch(op){
case 1:
x = read();
modify(l, r, x);
break;
case 2:
printf("%lld
", query(l, r));
break;
default:
puts("Invalid Command!");
break;
}
}
return 0;
}