4

Let A[1..n] be an array of real numbers. Design an algorithm to perform any sequence of the following operations:

Add(i,y) -- Add the value y to the ith number.
Partial-sum(i) -- Return the sum of the first i numbers, i.e.

There are no insertions or deletions; the only change is to the values of the numbers. Each operation should take O(logn) steps. You may use one additional array of size n as a work space.

How to design a data structure for above algorithm?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Sumer Cip
  • 179
  • 2
  • 11
  • 1
    If this is homework it should be tagged as such. – Howard Apr 19 '11 at 05:46
  • It is not a home work:) It is an exercise from Dr. Steven Skiena's great book: Algorithm Design Manual, Exercise 3.13. I could not come up with a good solution to this problem. That is why I am asking. – Sumer Cip Apr 19 '11 at 05:51
  • The input set is Let A[1..n] be an array of real numbers, Fenwick Tree requires the input set a constant maximum value. So, this is not a duplicate. – Sumer Cip Apr 19 '11 at 06:09
  • I'm a little confused - it says "You may use one additional array of size n as a workspace" - doesn't this mean your data structure has to be that array, or at least has to be represented inside that array? – Robin Green Apr 19 '11 at 07:37
  • If you look at the answer of ninjagecko, you will see that we build a binary tree on top of the values which has O(n) additional work space. – Sumer Cip Apr 19 '11 at 07:49
  • segment tree is the required data structure to solve the problem https://en.wikipedia.org/wiki/Segment_tree – akashchandrakar Feb 07 '16 at 16:48

2 Answers2

7

Construct a balanced binary tree with n leaves; stick the elements along the bottom of the tree in their original order.

Augment each node in the tree with "sum of leaves of subtree"; a tree has #leaves-1 nodes so this takes O(n) setup time (which we have).

Querying a partial-sum goes like this: Descend the tree towards the query (leaf) node, but whenever you descend right, add the subtree-sum on the left plus the element you just visited, since those elements are in the sum.

Modifying a value goes like this: Find the query (left) node. Calculate the difference you added. Travel to the root of the tree; as you travel to the root, update each node you visit by adding in the difference (you may need to visit adjacent nodes, depending if you're storing "sum of leaves of subtree" or "sum of left-subtree plus myself" or some variant); the main idea is that you appropriately update all the augmented branch data that needs updating, and that data will be on the root path or adjacent to it.

The two operations take O(log(n)) time (that's the height of a tree), and you do O(1) work at each node.

You can probably use any search tree (e.g. a self-balancing binary search tree might allow for insertions, others for quicker access) but I haven't thought that one through.

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • For Querying a partial-sum goes like this: Descend the tree just like binary search, but whenever you descend right, add the subtree-sum on the left, since we know for sure those elements are in the sum. I cannot understand the binary search part though. How to determine which way to branch? – Sumer Cip Apr 19 '11 at 07:28
  • Oops, rewritten slightly, there you go – ninjagecko Apr 19 '11 at 07:34
  • So, to descend towards the leaf node starting from root we need some kind of calculation right? – Sumer Cip Apr 19 '11 at 07:37
  • You know where the leaf node is (it is your input). You can follow its parents to the top of the tree, then go back down. If you don't want to do it that way, you can alternatively augment each node with the range on the left and the right so you can find your way. – ninjagecko Apr 19 '11 at 07:41
  • Hmm. I see. I thought there may be another exploitable fact to determine where to branch without any help. Thanks. – Sumer Cip Apr 19 '11 at 07:48
  • I still have a question: how to build correctly the tree? Given that n is a power of 2, you will have ~2^(n+1) nodes, for which you will have to select some keys. How do you select them? Also how can you guarantee that the array elements will go as leafs, when inserting them in the tree? – V G Aug 04 '13 at 22:21
  • Andrei I: `2^(levels-1) - 1 < nodes <= 2^levels - 1` (you claim that a tree can only have 2^(2^k+1) nodes). I think you can use any kind of search tree you want, and you can thus select nodes in any way you want. I talked about elements on the leaves merely because I was assuming a kind of binary search tree where they're only on the leaves. You can use a normal binary search tree and adapt it accordingly I think: each node has {array_index, array_value, sum_of_left_branch_and_me}. The question specifically said there would be no insertions, but you could probably use any self-balancing tree. – ninjagecko Aug 06 '13 at 09:44
2

You may use Fenwick Tree

See this question

Community
  • 1
  • 1
Maxim Razin
  • 9,114
  • 7
  • 34
  • 33
  • 1
    The input set is Let A[1..n] be an array of real numbers, Fenwick Tree requires the input set a constant maximum value. Answer should be something else, maybe another custom binary tree structure holding sum info... – Sumer Cip Apr 19 '11 at 06:10
  • 1
    I am not sure what you mean by 'the input set a constant maximum value'. I'm sure you're aware that computers use floats, which have both a maximum value and a maximum number of representable values. The notion of real numbers plays absolutely no part in your problem. (Well technically computers can 'represent' real numbers, just only finitely many.) – ninjagecko Apr 19 '11 at 06:26
  • 1
    From Wikipedia:A Fenwick tree is a tree that is indexed by the bits of the key for that tree. This tree can only be implemented for keys that are integers and have a fixed range. I just want to express that we do not have a fixed range mathematically. – Sumer Cip Apr 19 '11 at 06:38