1+ #include " LCA.h"
12#include < cstdio>
23#include < vector>
4+ #include < iostream>
5+ /* *
6+ *Constructor is initialized with a Adjacency List that
7+ *describe a tree and If It doesn't describe a tree it asserts failure.
8+ */
39
4- const int MAX_NODE = 5000 ;
5- const int MAX_LOG = 20 ;
6-
7- int numberOfNodes, maxLog;
8- std::vector< std::vector<int > > adjList;
9- int parent[MAX_NODE], nodeHeight[MAX_NODE];
10- bool visited[MAX_NODE];
11- int binaryLiftDp[MAX_NODE][MAX_LOG];
10+ LCA::LCA (std::vector< std::pair<int ,int > > edges): _numberOfNodes(edges.size() + 1), _maxLog(getMaxLog())
11+ {
12+ // First we initialize the needed vectors
13+ parent.resize (_numberOfNodes);
14+ nodeHeight.resize (_numberOfNodes);
15+ visited.resize (_numberOfNodes);
16+ adjList.resize (_numberOfNodes);
17+ binaryLiftDp = std::vector< std::vector<int > >(_numberOfNodes, std::vector<int >(_maxLog));
18+ /* *Construction of the Adjacency List to increase
19+ *The efficiency of the tree traversal to O(V + E).
20+ */
21+ for (auto edge : edges){
22+ adjList[edge.first ].push_back (edge.second );
23+ adjList[edge.second ].push_back (edge.first );
24+ }
25+ // Initialize the Dynamic programming Vector.
26+ initDP ();
27+ }
1228
13- void dfs (int currentNode, int currentParent)
29+ /* *
30+ *DFS is used to find the parent and the height of each node
31+ *allowing the use of Binary Lifting.
32+ */
33+ void LCA::dfs (int currentNode, int currentParent)
1434{
1535 visited[currentNode] = true ;
1636 parent[currentNode] = currentParent;
@@ -25,79 +45,73 @@ void dfs(int currentNode, int currentParent)
2545 }
2646}
2747
28- int getMaxLog (){
48+ /* *
49+ *Used to Calculate the Log to the base of two
50+ *for the number of the nodes to create the sparse table
51+ *used in binary Lifting.
52+ */
53+ int LCA::getMaxLog (){
2954 int curValue = 1 ;
3055 int curLog = 1 ;
31- while (curValue < numberOfNodes ) curValue *= 2 , curLog++;
56+ while (curValue < _numberOfNodes ) curValue *= 2 , curLog++;
3257 return curLog;
3358}
3459
35- void initializeDP ()
60+ void LCA::initDP ()
3661{
37- nodeHeight[-1 ] = -1 ;
38- maxLog = getMaxLog ();
3962 dfs (0 , -1 );
40- for (int i = 0 ; i < numberOfNodes ; i++) binaryLiftDp[i][0 ] = parent[i];
41- for (int i = 1 ; i <= maxLog ; i++)
63+ for (int i = 0 ; i < _numberOfNodes ; i++) binaryLiftDp[i][0 ] = parent[i];
64+ for (int i = 1 ; i <= _maxLog ; i++)
4265 {
43- for (int j = 0 ; j < numberOfNodes ; j++)
66+ for (int j = 0 ; j < _numberOfNodes ; j++)
4467 {
45- if (binaryLiftDp[j][i - 1 ] + 1 )
68+ /* *
69+ * Since the ith parent of the current node is equal to
70+ * the ith / 2 parent to the ith /2 parent of the current node
71+ * That's why the Recurrence relation is described as follow
72+ */
73+ if (binaryLiftDp[j][i - 1 ] != -1 )
4674 binaryLiftDp[j][i] = binaryLiftDp[binaryLiftDp[j][i - 1 ]][i - 1 ];
4775 else binaryLiftDp[j][i] = -1 ;
4876 }
4977 }
5078}
5179
52- int LCA (int a, int b)
80+ int LCA::lcaQuery (int a, int b)
5381{
82+ /* *
83+ * First Both nodes must have same height
84+ * So we will rise the node with the deeper height up in
85+ * the tree to where they're equal.
86+ */
5487 if (nodeHeight[a] < nodeHeight[b]) std::swap (a,b);
55- for (int i = maxLog ; i >= 0 ; i--)
88+ for (int i = _maxLog ; i >= 0 ; i--)
5689 {
5790 if (binaryLiftDp[a][i] + 1 && nodeHeight[binaryLiftDp[a][i]] >= nodeHeight[b])
5891 a = binaryLiftDp[a][i];
5992 }
60- if (!(a - b)) return a;
61- for (int i = maxLog; i >= 0 ; i--)
93+ /* *
94+ * If the node Lower is the LCA then return it.
95+ * Else keep moving both nodes up as much as they aren't the same
96+ * until it's only 1 node left which is the direct parent of both of them
97+ */
98+ if (a == b) return a;
99+ for (int i = _maxLog; i >= 0 ; i--)
62100 {
63101 if (binaryLiftDp[a][i] + 1 && binaryLiftDp[a][i] - binaryLiftDp[b][i])
64102 a = binaryLiftDp[a][i], b = binaryLiftDp[b][i];
65103 }
66104 return parent[a];
67105}
68106
69- void buildTree ()
70- {
71- printf (" Enter number of nodes of the tree: " );
72- scanf (" %d" , &numberOfNodes);
73- adjList.resize (numberOfNodes, std::vector<int > ());
74- for (int i = 0 ; i < numberOfNodes - 1 ; i++)
75- {
76- int firstNode, secondNode;
77- printf (" Enter the two nodes to be connected: " );
78- scanf (" %d %d" , &firstNode, &secondNode);
79- adjList[firstNode].push_back (secondNode);
80- adjList[secondNode].push_back (firstNode);
81- }
82- }
83-
84- void answerQueries ()
85- {
86- int queryCount;
87- printf (" Enter the number of queries: " );
88- scanf (" %d" , &queryCount);
89- for (int i = 0 ; i < queryCount; i++)
90- {
91- int firstNode, secondNode;
92- printf (" Enter the two nodes : " );
93- scanf (" %d %d" , &firstNode, &secondNode);
94- printf (" %d\n " , LCA (firstNode, secondNode));
95- }
96- }
97-
98- int main ()
99- {
100- buildTree ();
101- initializeDP ();
102- answerQueries ();
107+ int main (){
108+ std::vector< std::pair<int ,int > > edges;
109+ edges.push_back ({0 ,1 });
110+ edges.push_back ({1 ,2 });
111+ edges.push_back ({2 ,3 });
112+ edges.push_back ({1 ,4 });
113+ LCA* l = new LCA (v);
114+ std::cout << l->lcaQuery (0 ,1 ) << endl;
115+ std::cout << l->lcaQuery (3 ,4 ) << endl;
116+ std::cout << l->lcaQuery (3 ,2 ) << endl;
103117}
0 commit comments