Skip to content

Commit

Permalink
Merge pull request #1092 from SanikaBhalerao1345/main
Browse files Browse the repository at this point in the history
added heavy-light-algo in miscellaneous section
  • Loading branch information
pankaj-bind authored Oct 21, 2024
2 parents fbac230 + 6c1f4c0 commit c30fae9
Show file tree
Hide file tree
Showing 2 changed files with 243 additions and 0 deletions.
159 changes: 159 additions & 0 deletions Miscellaneous Algorithms/Heavy-light decomposition/Program.c
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 Miscellaneous Algorithms/Heavy-light decomposition/Readme.md
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.

0 comments on commit c30fae9

Please sign in to comment.