1
+ #include " LCA.h"
1
2
#include < cstdio>
2
3
#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
+ */
3
9
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
+ }
12
28
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)
14
34
{
15
35
visited[currentNode] = true ;
16
36
parent[currentNode] = currentParent;
@@ -25,79 +45,73 @@ void dfs(int currentNode, int currentParent)
25
45
}
26
46
}
27
47
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 (){
29
54
int curValue = 1 ;
30
55
int curLog = 1 ;
31
- while (curValue < numberOfNodes ) curValue *= 2 , curLog++;
56
+ while (curValue < _numberOfNodes ) curValue *= 2 , curLog++;
32
57
return curLog;
33
58
}
34
59
35
- void initializeDP ()
60
+ void LCA::initDP ()
36
61
{
37
- nodeHeight[-1 ] = -1 ;
38
- maxLog = getMaxLog ();
39
62
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++)
42
65
{
43
- for (int j = 0 ; j < numberOfNodes ; j++)
66
+ for (int j = 0 ; j < _numberOfNodes ; j++)
44
67
{
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 )
46
74
binaryLiftDp[j][i] = binaryLiftDp[binaryLiftDp[j][i - 1 ]][i - 1 ];
47
75
else binaryLiftDp[j][i] = -1 ;
48
76
}
49
77
}
50
78
}
51
79
52
- int LCA (int a, int b)
80
+ int LCA::lcaQuery (int a, int b)
53
81
{
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
+ */
54
87
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--)
56
89
{
57
90
if (binaryLiftDp[a][i] + 1 && nodeHeight[binaryLiftDp[a][i]] >= nodeHeight[b])
58
91
a = binaryLiftDp[a][i];
59
92
}
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--)
62
100
{
63
101
if (binaryLiftDp[a][i] + 1 && binaryLiftDp[a][i] - binaryLiftDp[b][i])
64
102
a = binaryLiftDp[a][i], b = binaryLiftDp[b][i];
65
103
}
66
104
return parent[a];
67
105
}
68
106
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;
103
117
}
0 commit comments