Tarjan 's off | number of nodes in input tree ; COLOUR ' WHITE ' is assigned value 1 ; COLOUR ' BLACK ' is assigned value 2 ; A binary tree node has data , pointer to left child and a pointer to right child ; subset [ i ] . parent - . Holds the parent of node - ' i ' subset [ i ] . rank - . Holds the rank of node - ' i ' subset [ i ] . ancestor - . Holds the LCA queries answers subset [ i ] . child - . Holds one of the child of node - ' i ' if present , else - '0' subset [ i ] . sibling - . Holds the right - sibling of node - ' i ' if present , else - '0' subset [ i ] . color - . Holds the colour of node - ' i ' ; Structure to represent a query A query consists of ( L , R ) and we will process the queries offline a / c to Tarjan 's oflline LCA algorithm ; Helper function that allocates a new node with the given data and null left and right pointers . ; A utility function to make set ; A utility function to find set of an element i ( uses path compression technique ) ; find root and make root as parent of i ( path compression ) ; A function that does union of two sets of x and y ( uses union by rank ) ; Attach smaller rank tree under root of high rank tree ( Union by Rank ) ; If ranks are same , then make one as root and increment its rank by one ; The main function that prints LCAs . u is root 's data. m is size of q[] ; Make Sets ; Initially , each node 's ancestor is the node  itself. ; This while loop doesn 't run for more than 2 times  as there can be at max. two children of a node ; This is basically an inorder traversal and we preprocess the arrays . child [ ] and sibling [ ] in " subset " with the tree structure using this function . ; Recur on left child ; Note that the below two lines can also be this - subsets [ node . data ] . child = node . right . data ; subsets [ node . right . data ] . sibling = node . left . data ; This is because if both left and right children of node - ' i ' are present then we can store any of them in subsets [ i ] . child and correspondingly its sibling ; Recur on right child ; A function to initialise prior to pre - processing and LCA walk ; We colour all nodes WHITE before LCA Walk . ; Prints LCAs for given queries q [ 0. . m - 1 ] in a tree with given root ; Allocate memory for V subsets and nodes ; Creates subsets and colors them WHITE ; Preprocess the tree ; Perform a tree walk to process the LCA queries offline ; We cona binary tree : - 1 / \ 2 3 / \ 4 5 ; LCA Queries to answer
let V = 5 ; let WHITE = 1 ; let BLACK = 2 ; class Node { constructor ( data ) { this . data = data ; this . left = this . right = null ; } } class subset { constructor ( ) { this . parent = 0 ; this . rank = 0 ; this . ancestor = 0 ; this . child = 0 ; this . sibling = 0 ; this . color = 0 ; } } class Query { constructor ( L , R ) { this . L = L ; this . R = R ; } } function newNode ( data ) { let node = new Node ( ) ; node . data = data ; node . left = node . right = null ; return ( node ) ; } function makeSet ( subsets , i ) { if ( i < 1 i > V ) return ; subsets [ i ] . color = WHITE ; subsets [ i ] . parent = i ; subsets [ i ] . rank = 0 ; return ; } function findSet ( subsets , i ) { if ( subsets [ i ] . parent != i ) subsets [ i ] . parent = findSet ( subsets , subsets [ i ] . parent ) ; return subsets [ i ] . parent ; } function unionSet ( subsets , x , y ) { let xroot = findSet ( subsets , x ) ; let yroot = findSet ( subsets , y ) ; if ( subsets [ xroot ] . rank < subsets [ yroot ] . rank ) subsets [ xroot ] . parent = yroot ; else if ( subsets [ xroot ] . rank > subsets [ yroot ] . rank ) subsets [ yroot ] . parent = xroot ; else { subsets [ yroot ] . parent = xroot ; ( subsets [ xroot ] . rank ) ++ ; } } function lcaWalk ( u , q , m , subsets ) { makeSet ( subsets , u ) ; subsets [ findSet ( subsets , u ) ] . ancestor = u ; let child = subsets [ u ] . child ; while ( child != 0 ) { lcaWalk ( child , q , m , subsets ) ; unionSet ( subsets , u , child ) ; subsets [ findSet ( subsets , u ) ] . ancestor = u ; child = subsets [ child ] . sibling ; } subsets [ u ] . color = BLACK ; for ( let i = 0 ; i < m ; i ++ ) { if ( q [ i ] . L == u ) { if ( subsets [ q [ i ] . R ] . color == BLACK ) { document . write ( " " + q [ i ] . L + " " + q [ i ] . R + " " , subsets [ findSet ( subsets , q [ i ] . R ) ] . ancestor + " " ) ; } } else if ( q [ i ] . R == u ) { if ( subsets [ q [ i ] . L ] . color == BLACK ) { document . write ( " " + q [ i ] . L + " " + q [ i ] . R + " " , subsets [ findSet ( subsets , q [ i ] . L ) ] . ancestor + " " ) ; } } } return ; } function preprocess ( node , subsets ) { if ( node == null ) return ; preprocess ( node . left , subsets ) ; if ( node . left != null && node . right != null ) { subsets [ node . data ] . child = node . left . data ; subsets [ node . left . data ] . sibling = node . right . data ; } else if ( ( node . left != null && node . right == null ) || ( node . left == null && node . right != null ) ) { if ( node . left != null && node . right == null ) subsets [ node . data ] . child = node . left . data ; else subsets [ node . data ] . child = node . right . data ; } preprocess ( node . right , subsets ) ; } function initialise ( subsets ) { for ( let i = 1 ; i < subsets . length ; i ++ ) { subsets [ i ] = new subset ( ) ; subsets [ i ] . color = WHITE ; } return ; } function printLCAs ( root , q , m ) { let subsets = new Array ( V + 1 ) ; initialise ( subsets ) ; preprocess ( root , subsets ) ; lcaWalk ( root . data , q , m , subsets ) ; } let root = newNode ( 1 ) ; root . left = newNode ( 2 ) ; root . right = newNode ( 3 ) ; root . left . left = newNode ( 4 ) ; root . left . right = newNode ( 5 ) ; let q = new Array ( 3 ) ; q [ 0 ] = new Query ( 5 , 4 ) ; q [ 1 ] = new Query ( 1 , 3 ) ; q [ 2 ] = new Query ( 2 , 3 ) ; let m = q . length ; printLCAs ( root , q , m ) ;