1

I came across this question in a contest (which is now over) and I am not able to think of a time-efficient algorithm.

You are given a rooted Tree of N ( <=10^5) nodes . Initially all nodes have value 0.There would be M updates (<=10^5) to the tree which are of the form

Add x y – Add y to node x .

AddUp x y – Add y to x , parent of x , parent of parent of x uptill Root.

After that there will be Q queries ( <=10^5) queries where you will either be asked to give the value of a node or the sum of subtree rooted at that node.

What I did:-

First I tried the naive algorithm that would update each node according to the operation, but obviously it is time taking.

I also thought of using segment trees and Lazy propogation but cannot think of a proper way.

Any help is appreciated , Thanks!

Alzio
  • 45
  • 9

3 Answers3

1

First, construct a graph where the children point to their parents. After that, parse all the updates and store in each node of your tree the sum of Add and AddUp separately. Your node should have the following variables:

sum_add : the sum of all the Add of this node
sum_add_up : the sum of all the AddUp of this node
subtree_sum : the sum of the subtree. Initialize with 0 by now.

Now, transverse your graph using topological order, i.e., you will only process a node if all of its children were already processed, which takes O(N). Let me now define the process function.

process(V) {
    V.sum_add_up = V.sum_add_up + sum(sum_add_up of all V.children)
    V.subtree_sum = V.sum_add + V.sum_add_up + sum(subtree_sum of all V.children)
}

Now you can answer all the queries in O(1). The query for the value of a node V is V.sum_add + V.sum_add_up, and the query for the subtree of V is just V.subtree_sum.

Gabriel Gava
  • 571
  • 4
  • 10
  • Let me know if you want it to be more formal, or if you need me to prove the time complexity of it. – Gabriel Gava Oct 24 '17 at 20:28
  • Hi Gabriel , I will go through your solution and try to understand it . Thank you very much for the help!! – Alzio Oct 24 '17 at 20:51
1

This is a Fenwick Tree, for solve this kind of problems you must to execute a topological sort on tree and count the number of childrens for each node.

      0
    /   \
   1     2
  / \
 3   4

index: [0 1,2,3,4] childrens: [4,2,0,0,0] With topological you will obtain this vector 0 1 3 4 2 you need to reverse it:

fenwick Pos:  [0,1,2,3,4]
vector values:[2,4,3,1,0]
pos: [5,3,0,2,1]

With fenwick tree you can execute 2 kinds of query, update query, range sum query when you need to update a only a index call update(pos[index], y), then you must decrease all next values, update(pos[index]+1, -y) When you need to update all parents call update(pos[index], y) and update(pos[index] + childrens[index] + 1, -y);

for know value of a position you need to call range sum query on pos[index]

Cat
  • 11
  • 1
0

I think this problem is just a direct application of a Binary Search Tree, which has an average-case cost (after n random operations) O(1.39log(n)) for both inserts and queries.

All you have to do is recursively add new nodes and update values and sum at the same time.

Implementation is also fairly simple (sorry for C#), for example for Add() (AddUp() is similar - increase value every time you go to left or right subtree):

public void Add(int key, int value)
{
    Root = Add(Root, key, value);
}

private Node Add(Node node, int key, int value)
{
    if (node == null)
    {
        node = new Node(key, value, value);
    }

    if (key < node.Key)
    {
        node.Left = Add(node.Left, key, value);
    }
    else if (key > node.Key)
    {
        node.Right = Add(node.Right, key, value);
    }
    else
    {
        node.Value = value;
    }

    node.Sum = Sum(node.Left) + Sum(node.Right) + node.Value;

    return node;
}

For 100000 numbers on my machine this translates to these numbers:

Added(up) 100000 values in: 213 ms, 831985 ticks
Got 100000 values in:       86 ms, 337072 ticks

And for 1 million numbers:

Added(up) 1000000 values in: 3127 ms, 12211606 ticks
Got 1000000 values in:       1244 ms, 4857733 ticks

Is this time efficient enough? You can try complete code here.

Sergei G
  • 1,550
  • 3
  • 24
  • 44