$\newcommand{\O}{\mathrm{O}}$
BIT を $2$ つ持つことで, 区間加算, 区間和 のクエリを $\O (\log n)$ で処理するデータ構造を実現できる. 実測がどっちが速いかはテストケースによる(こちらは区間加算の定数倍が少し重い).
$1$ つの BIT で区間加算, ある $1$ 点の値を求める というクエリを処理するやつ(imos 的にやるとできる)の応用版.
区間に線形関数を足すことができればよくてそれは $1$ 次の係数と定数項それぞれについて BIT を持てば実現可能.
時間計算量: 構築 $\O (n)$, クエリ $\O (\log n)$
template<typename T> class BIT { private: int n; vector<T> bit; public: void add(int i, const T x){ i++; while(i < n){ bit[i] += x, i += i & -i; } } T sum(int i) const { i++; T s = 0; while(i > 0){ s += bit[i], i -= i & -i; } return s; } BIT(const int sz) : n(sz + 1), bit(n, 0){} }; template<typename T> class BIT_1D_RangeAdd_RangeSum { private: int n; BIT<T> bitc, biti; public: // 初期値はすべて 0 BIT_1D_RangeAdd_RangeSum(const int sz) : n(sz), bitc(sz), biti(sz){} // [l, r) に val を加算 void add(const int l, const int r, const T val){ bitc.add(l, val), bitc.add(r, -val); biti.add(l, -val * (l - 1)), biti.add(r, val * (r - 1)); } // [0, x] の和 T sum(const int x) const { return bitc.sum(x) * x + biti.sum(x); } // [l, r) の和 T sum(const int l, const int r) const { return sum(r-1) - sum(l-1); } void print(){ for(int i = 0; i < n; i++){ cout << sum(i, i+1) << " "; } cout << "\n"; } };
AOJ : RSQ and RAQ 提出コード