树状数组实现区间修改查询
一般的树状数组对于可减信息可以实现单点修改+区间查询,如果套用差分,可以实现区间修改+单点查询。
同时实现区间修改和查询的方法
设要维护的序列\(a\),差分数组\(d_i = a_i - a_{i-1}\)
要求\([1, x]\)区间的和:
\[\begin{aligned}
query(x) &=
\sum_{i=1}^x a_i \\&= \sum_{i=1}^x \sum_{j=1}^i d_i \\
&= \sum_{i=1}^x (x-i+1)d_i
\end{aligned}
\]
维护一个序列\(ds_i = (i-1)d_i\)
则和为\(x \sum_{i=1}^x d_i - \sum_{i=1}^xds_i\)
Code
不要对这个压行!虽然每行代码都很短,但可能会出事!
很可能原来写的int
改long long
就会忘改
ll d[Len2], ds[Len2];
int BITLen;
inline void modifyT(ll *t, int p, ll x){
for(; p<=BITLen; p += p & -p) t[p] += x;
}
inline ll queryT(ll *t, int p){
ll r = 0;
for(; p; p ^= (p & -p)) r += t[p];
return r;
}
inline void modify(int p, ll x){
if(p <= BITLen)
modifyT(d, p, x), modifyT(ds, p, x * (p - 1));
}
inline ll query(int p){
if(p < 0) return 0;
p = min(p, BITLen);
return p * queryT(d, p) - queryT(ds, p);
}
UPD: 补一个常数比较小,代码很短的实现
struct dual_bit {
struct { ll d, ds; } t[N];
void modify(int p, int v) {
ll vp = v * (p - 1);
for (; p <= n; p += p & -p)
t[p].d += v, t[p].ds += vp;
}
ll prefix(int p) {
ll s = 0, sp = 0;
for (int q = p; q; q &= q - 1)
s += t[q].d, sp += t[q].ds;
return s * p - sp;
}
};
打一些题很方便,比线段树友好多了,常数也小