Source code for tryalgo.fenwick

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""\
Fenwick tree

jill-jenn vie et christoph durr - 2014-2018
"""


# snip{
[docs] class Fenwick: """maintains a tree to allow quick updates and queries """ def __init__(self, t): """stores a table t and allows updates and queries of prefix sums in logarithmic time. :param array t: with numerical values """ self.s = [0] * (len(t) + 1) # create internal storage for a, v in enumerate(t): self.add(a, v) # initialize # pylint: disable=redefined-builtin
[docs] def prefixSum(self, a): """ :param int a: index in t, negative a will return 0 :returns: t[0] + ... + t[a] """ i = a + 1 # internal index starts at 1 total = 0 while i > 0: # loops over neighbors total += self.s[i] # cumulative sum i -= (i & -i) # left neighbor return total
[docs] def intervalSum(self, a, b): """ :param int a b: with 0 <= a <= b :returns: t[a] + ... + t[b] """ return self.prefixSum(b) - self.prefixSum(a-1)
[docs] def add(self, a, val): """ :param int a: index in t :modifies: adds val to t[a] """ i = a + 1 # internal index starts at 1 while i < len(self.s): # loops over parents self.s[i] += val # update node i += (i & -i) # parent
# variante: # pylint: disable=bad-whitespace
[docs] def intervalAdd(self, a, b, val): """Variant, adds val to t[a], to t[a + 1] ... and to t[b] :param int a b: with 0 <= a <= b < len(t) """ self.add(a, +val) self.add(b + 1, -val)
[docs] def get(self, a): """Variant, reads t[a] :param int i: negative a will return 0 """ return self.prefixSum(a)
# snip}
[docs] class FenwickMin: """maintains a tree to allow quick updates and queries of a virtual table t """ def __init__(self, size): """stores a table t and allows updates and queries of prefix sums in logarithmic time. :param size: length of the table """ self.s = [float('+inf')] * (size + 1) # create internal storage
[docs] def prefixMin(self, a): """ :param int a: index in t, negative a will return infinity :returns: min(t[0], ... ,t[a]) """ i = a + 1 # internal index starts at 1 retval = float('+inf') while i > 0: # loops over neighbors retval = min(retval, self.s[i]) i -= (i & -i) # left neighbor return retval
[docs] def update(self, a, val): """ :param int a: index in t :param val: a value :modifies: sets t[a] to the minimum of t[a] and val """ i = a + 1 # internal index starts at 1 while i < len(self.s): # loops over parents self.s[i] = min(self.s[i], val) # update node i += (i & -i) # parent