BITはセグメント木の機能を限定したものであり、実装が簡単でメモリを節約できる
//数列a(a[0],a[1],…,a[n-1])についての区間和と点更新を扱う
//区間和,点更新,二分探索はO(log{n})で動作する
class BIT {
public:
//データの長さ
ll n;
//データの格納先
vector<ll> a;//(1の最小bitの桁)個数分の範囲和を持つ
//コンストラクタ
BIT(ll n) :n(n), a(n + 1, 0) {}
//a[i]にxを加算する
void add(ll i, ll x) {
i++;
if (i == 0) return;
for (ll k = i;k <= n;k += (k & -k)) {//下から上
a[k] += x;
}
}
//a[i]+a[i+1]+…+a[j]を求める
ll sum(ll i, ll j) {
return sum_sub(j) - sum_sub(i - 1);
}
//a[0]+a[1]+…+a[i]を求める
ll sum_sub(ll i) {
i++;
ll s = 0;
if (i == 0) return s;
for (ll k = i;k > 0;k -= (k & -k)) {//上から下
s += a[k];
}
return s;
}
//a[0]+a[1]+…+a[i]>=xとなる最小のiを求める(任意のkでa[k]>=0が必要)
ll lower_bound(ll x) {
if (x <= 0) {
//xが0以下の場合は該当するものなし→0を返す
return 0;
}
else {
ll i = 0;ll r = 1;
//最大としてありうる区間の長さを取得する
//n以下の最小の二乗のべき(BITで管理する数列の区間で最大のもの)を求める
while (r < n) r = r << 1;
//区間の長さは調べるごとに半分になる
for (int len = r;len > 0;len = len >> 1) {
//その区間を採用する場合
if (i + len < n && a[i + len] < x) {
x -= a[i + len];
i += len;
}
}
return i;
}
}
};