树状数组实现区间修改查询

一般的树状数组对于可减信息可以实现单点修改+区间查询,如果套用差分,可以实现区间修改+单点查询。

同时实现区间修改和查询的方法

设要维护的序列\(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

不要对这个压行!虽然每行代码都很短,但可能会出事!
很可能原来写的intlong 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;
  }
};

打一些题很方便,比线段树友好多了,常数也小

posted @ 2019-04-24 20:33  RiverHamster  阅读(321)  评论(0编辑  收藏  举报
\