差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン次のリビジョン両方とも次のリビジョン | ||
programming_algorithm:data_structure:binary_indexed_tree [2020/12/13] – [より柔軟な実装] ikatakos | programming_algorithm:data_structure:binary_indexed_tree [2021/06/17] – ikatakos | ||
---|---|---|---|
行 10: | 行 10: | ||
* 以下の2つの要求を処理する | * 以下の2つの要求を処理する | ||
* $a_i$ に $x$ を加算($1 \le i \le N$) | * $a_i$ に $x$ を加算($1 \le i \le N$) | ||
- | * $a_s~a_t$ の合計を得る($1 \le s \le t \le N$) | + | * $a_1~a_i$ の合計を得る($1 \le i \le N$) |
Binary Indexed Treeは、この2つを高速に行える。 | Binary Indexed Treeは、この2つを高速に行える。 | ||
+ | |||
+ | 合計が $a_1$ からの合計しか得られない制約があるが、$sum(a_1~a_{s-1})-sum(a_1~a_t) = sum(a_s~a_t)$ なので、2回やれば任意区間の合計が得られる。 | ||
これだけ見ると「そんなのが何の役に立つの?」って感じだが、頭のいい人だと全然関係ないように見える問題を変換して効率的に解いたりしちゃうらしい。 | これだけ見ると「そんなのが何の役に立つの?」って感じだが、頭のいい人だと全然関係ないように見える問題を変換して効率的に解いたりしちゃうらしい。 | ||
行 90: | 行 92: | ||
self.func = func | self.func = func | ||
self.idf = identity_factory | self.idf = identity_factory | ||
- | self.depth = n.bit_length() | ||
def add(self, i, x): | def add(self, i, x): | ||
行 108: | 行 109: | ||
return s | return s | ||
- | def lower_bound(self, | ||
- | """ | ||
- | 累積和がx以上になる最小のindexと、その直前までの累積和(未検証) | ||
- | |||
- | :param lt: lt(a, b) で a < b ならTrueを返す関数 | ||
- | """ | ||
- | total = self.idf() | ||
- | pos = 0 | ||
- | tree = self.tree | ||
- | func = self.func | ||
- | for i in range(self.depth, | ||
- | k = pos + (1 << i) | ||
- | new_total = func(total, tree[k]) | ||
- | if k <= self.size and lt(new_total, | ||
- | total = new_total | ||
- | pos += 1 << i | ||
- | return pos + 1, total | ||
</ | </ | ||
- | listやdictなどのオブジェクトを載せることもできる。\\ | + | 実装について補足。 |
+ | |||
+ | Fenwick木では、listやdictなどのオブジェクトを載せることもできる。\\ | ||
その場合の注意点として、Pythonでは、オブジェクトを特に工夫無くコピーするとインスタンス自体が同じとなる。つまりどれか1つへの反映が他の全てに反映されてしまう。 | その場合の注意点として、Pythonでは、オブジェクトを特に工夫無くコピーするとインスタンス自体が同じとなる。つまりどれか1つへの反映が他の全てに反映されてしまう。 | ||
行 274: | 行 260: | ||
</ | </ | ||
+ | |||
+ | ++++ Injectable版 | | ||
+ | |||
+ | <sxh python> | ||
+ | class FenwickTreeInjectable: | ||
+ | def __init__(self, | ||
+ | self.size = n | ||
+ | self.tree = [identity_factory() for _ in range(n + 1)] | ||
+ | self.func = func | ||
+ | self.idf = identity_factory | ||
+ | self.depth = n.bit_length() | ||
+ | |||
+ | def add(self, i, x): | ||
+ | tree = self.tree | ||
+ | func = self.func | ||
+ | while i <= self.size: | ||
+ | tree[i] = func(tree[i], | ||
+ | i += i & -i | ||
+ | |||
+ | def sum(self, i): | ||
+ | s = self.idf() | ||
+ | tree = self.tree | ||
+ | func = self.func | ||
+ | while i > 0: | ||
+ | s = func(s, tree[i]) | ||
+ | i -= i & -i | ||
+ | return s | ||
+ | |||
+ | def lower_bound(self, | ||
+ | """ | ||
+ | 累積和がx以上になる最小のindexと、その直前までの累積和(未検証) | ||
+ | |||
+ | :param lt: lt(a, b) で a < b ならTrueを返す関数 | ||
+ | """ | ||
+ | total = self.idf() | ||
+ | pos = 0 | ||
+ | tree = self.tree | ||
+ | func = self.func | ||
+ | for i in range(self.depth, | ||
+ | k = pos + (1 << i) | ||
+ | new_total = func(total, tree[k]) | ||
+ | if k <= self.size and lt(new_total, | ||
+ | total = new_total | ||
+ | pos += 1 << i | ||
+ | return pos + 1, total | ||
+ | </ | ||
+ | |||
+ | ++++ | ||