-
Notifications
You must be signed in to change notification settings - Fork 302
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1092 from SanikaBhalerao1345/main
added heavy-light-algo in miscellaneous section
- Loading branch information
Showing
2 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
159 changes: 159 additions & 0 deletions
159
Miscellaneous Algorithms/Heavy-light decomposition/Program.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#define MAXN 100005 | ||
|
||
typedef struct { | ||
int v; | ||
struct Node *next; | ||
} Node; | ||
|
||
Node *tree[MAXN]; | ||
int parent[MAXN], depth[MAXN], heavy[MAXN], head[MAXN], pos[MAXN]; | ||
int currentPos; | ||
int segmentTree[4 * MAXN], values[MAXN]; // Segment tree to support range queries | ||
int subtreeSize[MAXN]; | ||
|
||
// Utility function to add an edge in the adjacency list | ||
void addEdge(int u, int v) { | ||
Node *newNode = (Node *)malloc(sizeof(Node)); | ||
newNode->v = v; | ||
newNode->next = tree[u]; | ||
tree[u] = newNode; | ||
} | ||
|
||
// DFS to calculate subtree sizes and find heavy child for each node | ||
int dfs(int v) { | ||
int size = 1; | ||
int maxSubtree = 0; | ||
subtreeSize[v] = 1; | ||
|
||
for (Node *node = tree[v]; node != NULL; node = node->next) { | ||
int u = node->v; | ||
if (u != parent[v]) { | ||
parent[u] = v; | ||
depth[u] = depth[v] + 1; | ||
int subtreeSize = dfs(u); | ||
size += subtreeSize; | ||
if (subtreeSize > maxSubtree) { | ||
maxSubtree = subtreeSize; | ||
heavy[v] = u; | ||
} | ||
} | ||
} | ||
return size; | ||
} | ||
|
||
// Decomposing the tree into heavy-light chains | ||
void decompose(int v, int h) { | ||
head[v] = h; | ||
pos[v] = currentPos++; | ||
if (heavy[v] != -1) { | ||
decompose(heavy[v], h); // Continue on the heavy path | ||
} | ||
for (Node *node = tree[v]; node != NULL; node = node->next) { | ||
int u = node->v; | ||
if (u != parent[v] && u != heavy[v]) { | ||
decompose(u, u); // Start a new light path | ||
} | ||
} | ||
} | ||
|
||
// Building the segment tree for range queries | ||
void buildSegmentTree(int node, int start, int end) { | ||
if (start == end) { | ||
segmentTree[node] = values[start]; | ||
} else { | ||
int mid = (start + end) / 2; | ||
buildSegmentTree(2 * node, start, mid); | ||
buildSegmentTree(2 * node + 1, mid + 1, end); | ||
segmentTree[node] = segmentTree[2 * node] + segmentTree[2 * node + 1]; | ||
} | ||
} | ||
|
||
// Segment tree update function | ||
void updateSegmentTree(int node, int start, int end, int idx, int value) { | ||
if (start == end) { | ||
segmentTree[node] = value; | ||
} else { | ||
int mid = (start + end) / 2; | ||
if (idx <= mid) { | ||
updateSegmentTree(2 * node, start, mid, idx, value); | ||
} else { | ||
updateSegmentTree(2 * node + 1, mid + 1, end, idx, value); | ||
} | ||
segmentTree[node] = segmentTree[2 * node] + segmentTree[2 * node + 1]; | ||
} | ||
} | ||
|
||
// Segment tree query function | ||
int querySegmentTree(int node, int start, int end, int l, int r) { | ||
if (r < start || end < l) { | ||
return 0; | ||
} | ||
if (l <= start && end <= r) { | ||
return segmentTree[node]; | ||
} | ||
int mid = (start + end) / 2; | ||
int leftSum = querySegmentTree(2 * node, start, mid, l, r); | ||
int rightSum = querySegmentTree(2 * node + 1, mid + 1, end, l, r); | ||
return leftSum + rightSum; | ||
} | ||
|
||
// Querying the path from node u to v | ||
int queryPath(int u, int v) { | ||
int result = 0; | ||
while (head[u] != head[v]) { | ||
if (depth[head[u]] < depth[head[v]]) { | ||
int temp = u; | ||
u = v; | ||
v = temp; | ||
} | ||
result += querySegmentTree(1, 0, currentPos - 1, pos[head[u]], pos[u]); | ||
u = parent[head[u]]; | ||
} | ||
if (depth[u] > depth[v]) { | ||
int temp = u; | ||
u = v; | ||
v = temp; | ||
} | ||
result += querySegmentTree(1, 0, currentPos - 1, pos[u], pos[v]); | ||
return result; | ||
} | ||
|
||
int main() { | ||
int n; | ||
scanf("%d", &n); // Number of nodes | ||
|
||
// Initialize variables | ||
memset(tree, 0, sizeof(tree)); | ||
memset(heavy, -1, sizeof(heavy)); | ||
currentPos = 0; | ||
|
||
// Read tree edges | ||
for (int i = 0; i < n - 1; i++) { | ||
int u, v; | ||
scanf("%d %d", &u, &v); | ||
addEdge(u, v); | ||
addEdge(v, u); | ||
} | ||
|
||
// Initialize parent and depth | ||
parent[0] = -1; | ||
depth[0] = 0; | ||
|
||
// Perform DFS and decompose the tree | ||
dfs(0); | ||
decompose(0, 0); | ||
|
||
// Build segment tree with initial values | ||
buildSegmentTree(1, 0, currentPos - 1); | ||
|
||
// Example query and update usage | ||
int u, v; | ||
scanf("%d %d", &u, &v); | ||
printf("Path sum between %d and %d is %d\n", u, v, queryPath(u, v)); | ||
|
||
return 0; | ||
} |
84 changes: 84 additions & 0 deletions
84
Miscellaneous Algorithms/Heavy-light decomposition/Readme.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
|
||
# Heavy-Light Decomposition in C | ||
|
||
This repository contains a C implementation of the Heavy-Light Decomposition (HLD) algorithm. HLD is used for decomposing a tree to efficiently handle path queries and updates. This implementation supports querying the sum of values along the path between two nodes. | ||
|
||
## Overview | ||
|
||
Heavy-Light Decomposition is a technique used to decompose a tree into "heavy" and "light" paths. This allows for efficient querying and updating along the paths, using segment trees to handle range queries. | ||
|
||
### Key Features: | ||
- Handles tree-based queries efficiently using HLD. | ||
- Supports path sum queries and updates using a segment tree. | ||
|
||
## Input | ||
|
||
The program expects the following input format: | ||
1. **Number of Nodes (n)**: The first input line contains a single integer `n`, representing the number of nodes in the tree. | ||
2. **Tree Edges**: The next `n-1` lines contain two integers `u` and `v`, representing an undirected edge between nodes `u` and `v`. This describes the tree's structure. | ||
3. **Query Nodes (u, v)**: A pair of integers representing the nodes between which the path sum is queried. | ||
|
||
### Example Input | ||
|
||
5 0 1 1 2 1 3 3 4 2 4 | ||
|
||
This input represents: | ||
- A tree with 5 nodes. | ||
- Edges: (0-1), (1-2), (1-3), (3-4). | ||
- A path sum query between nodes 2 and 4. | ||
|
||
## Output | ||
|
||
The output displays the sum of the values along the path between the specified nodes. Initially, all node values are set to zero. The segment tree can be updated to reflect different values for each node, allowing for more meaningful results. | ||
|
||
### Example Output | ||
|
||
Path sum between 2 and 4 is 0 | ||
|
||
In this example, the initial values are set to zero, resulting in a path sum of zero between nodes 2 and 4. | ||
|
||
## How to Run | ||
|
||
1. **Compile the Program**: Use a C compiler like `gcc`. | ||
```bash | ||
gcc -o hld hld.c | ||
``` | ||
2. **Run the Program**: Provide input according to the format specified above. | ||
```bash | ||
./hld | ||
``` | ||
|
||
3. **Sample Execution**: | ||
``` | ||
Input: | ||
5 | ||
0 1 | ||
1 2 | ||
1 3 | ||
3 4 | ||
2 4 | ||
|
||
Output: | ||
Path sum between 2 and 4 is 0 | ||
``` | ||
|
||
## Code Explanation | ||
|
||
### Functions: | ||
1. **addEdge**: Adds an edge in the adjacency list representation of the tree. | ||
2. **Depth-First Search (DFS)**: Computes subtree sizes and identifies the heavy child for each node. | ||
3. **decompose**: Decomposes the tree into heavy and light chains. | ||
4. **buildSegmentTree**: Builds the segment tree for range queries. | ||
5. **updateSegmentTree**: Updates a value in the segment tree. | ||
6. **querySegmentTree**: Queries the sum of values in a range using the segment tree. | ||
7. **queryPath**: Finds the sum of values along the path from node `u` to node `v`. | ||
|
||
## Additional Notes | ||
|
||
- Ensure the input tree is connected and acyclic, satisfying tree properties. | ||
- Nodes are indexed from 0 to n-1. | ||
- The program can be extended to support additional queries like maximum or minimum values along a path. | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License. See the `LICENSE` file for details. |