devsda
devsda

Reputation: 4222

Identify node lies between two other node

Tree is given. Edges information is given as a adjacency list format.

Nodes numbers are in 1, 2, 3, ....N.

Root of the tree is 1 always.

Now, two indices are given. Question is wheather any index of the above two lies on the ways from root (1) to other index.

Constraints

  1. Numbers of nodes is 10^5.
  2. Maximum Queries that can fire, 10^5.
  3. Parent Id is always smaller than child.

Example :-

Edges given :-

1 2
2 5
1 3
3 7
1 4
4 8
8 9

Questions -

2 3  ( Answer - Not possible, from 1 to 2, 3 never comes in between and from 1 to 3, 2 never comes in between.)
8 9  ( Answer - Possible, 8 lies in between 1 and 9)

Next example :-

1 2
2 4
2 5
1 3
3 6
3 7
3 8

Upvotes: 1

Views: 151

Answers (3)

Beta
Beta

Reputation: 99094

For each node, construct a sorted list of the nodes above it in the tree:

1 {}
2 {1}
3 {1}
4 {1}
5 {1, 2}
7 {1, 3}
8 {1, 4}
9 {1, 4, 8}

Then, when when given a query, search for each node in the list belonging to the other (O(logN)):

2 3: 2 is not in {1}, and 3 is not in {1}, so the answer is no.
8 9: 9 is not in {1, 4}, but 8 is in {1, 4, 8}, so the answer is yes.

EDIT:

As tobias_k points out, there are other structures such as a hash table which would make the search O(1). And constructing the table is O(n), trivially-- just iterate over the list of edges and put 'em in.

Upvotes: 0

tobias_k
tobias_k

Reputation: 82899

Assuming that the ID of the parent node (the one closer to the root) is always greater than the ID of the child node, as it seems to be the case in your examples, you can easily see from any edge whether it leads towards the root or away from it. Thus the basic algorithms would be:

given nodes n and m
find edge (x, n) or (n, x) such that x < n
repeat with node x until x is m or x is root

I don't think there is a faster way to find out whether one node is 'between' root and the other. You can, of course, improve performance by using appropriate data structures, e.g by first mapping each node to its parent in a hash set. Here's an example in Python:

ROOT = 1
edges = ((1, 2), (2, 4), (2, 5), (1, 3), (3, 6), (3, 7), (3, 8))

parents = {}
for edge in edges:
    parent, child = min(edge), max(edge)
    parents[child] = parent

def is_anchestor_of(p, c):
    while c > p:
        if parents[c] == p:
            return True
        c = parents[c]
    return False

Complexity in both, time and space, for creating the hash map is O(n) in the number of nodes or edges (which is pretty much the same in a tree), and average case complexity for is_anchestor_of is O(logn), but can deteriorate to O(n) in the worst case (extremely unbalanced tree, or chain).

You can improve the lookup complexity by mapping each node to all of it's anchestors. Complexity for creating this hash map would be O(n log n), unless I'm mistaken, both time and space, but could probably go up to O(n^2) in the worst case. In any case, using this structure, the complexity of is_anchestor_of is O(1), since it is just a lookup in a hash map followed by a lookup in a hash set.

anchestors = {}
for node in parents:
    anchestors[node] = set([ ROOT ])
    p = parents[node]
    while p != ROOT:
        anchestors[node].add(p)
        p = parents[p]

def is_anchestor_of(p, c):
    return p in anchestors[c]

In both cases, just check whether one is an anchestor of the other.

def on_one_path(x, y):
    return is_anchestor_of(x, y) if x < y else is_anchestor_of(y, x)
print on_one_path(3, 8)

Update: Seems there is a more efficient approach; see @Loha's answer.

Upvotes: 1

Loha
Loha

Reputation: 50

Algorithm is as follows :-

  1. Start from root, and note IN TIME and OUT TIME for each and every node. As you said Adjacency list is given. That you can easily done by using DFS in Time complexity O(Total number of nodes ).
  2. One node "B" is descendent to other node "A", only in one condition.

    IN_TIME(A) < IN_TIME(B) and OUT_TIME(B) < OUT_TIME(A)

This way, Query will handle in O(1) time.

Upvotes: 1

Related Questions