Skip to content

Commit

Permalink
Merge pull request #1459 from divyalakshmi0/main
Browse files Browse the repository at this point in the history
Added Mo's Algorithm for Efficient Range Queries
  • Loading branch information
pankaj-bind authored Oct 30, 2024
2 parents e059301 + 430ac4d commit a71ed0c
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
105 changes: 105 additions & 0 deletions 1D Arrays/Mo's Algorithm/Program.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAX_N 100000
#define MAX_Q 100000

// Structure for each query
typedef struct {
int L, R, idx;
} Query;

int n, q;
int arr[MAX_N];
Query queries[MAX_Q];
int answer[MAX_Q];
int current_answer = 0;
int freq[1000001];

// Comparator function to sort queries by Mo's ordering
int compare(const void *a, const void *b) {
Query *q1 = (Query *)a;
Query *q2 = (Query *)b;
int block1 = q1->L / (int)sqrt(n);
int block2 = q2->L / (int)sqrt(n);
if (block1 != block2) {
return block1 - block2;
}
return (block1 & 1) ? (q1->R - q2->R) : (q2->R - q1->R);
}

// Function to add element at index pos
void add(int pos) {
current_answer += arr[pos];
}

// Function to remove element at index pos
void remove(int pos) {
current_answer -= arr[pos];
}

// Mo's Algorithm to answer all queries
void mo_algorithm() {
int currentL = 0, currentR = -1;
for (int i = 0; i < q; i++) {
int L = queries[i].L;
int R = queries[i].R;

// Adjust the left boundary
while (currentL < L) {
remove(currentL);
currentL++;
}
while (currentL > L) {
currentL--;
add(currentL);
}

// Adjust the right boundary
while (currentR < R) {
currentR++;
add(currentR);
}
while (currentR > R) {
remove(currentR);
currentR--;
}

// Store the answer for this query
answer[queries[i].idx] = current_answer;
}
}

int main() {
// Input array size and elements
printf("Enter the size of the array: ");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Input number of queries and their ranges
printf("Enter the number of queries: ");
scanf("%d", &q);
for (int i = 0; i < q; i++) {
scanf("%d %d", &queries[i].L, &queries[i].R);
queries[i].L--; // Convert to zero-based indexing
queries[i].R--;
queries[i].idx = i;
}

// Sort queries according to Mo's ordering
qsort(queries, q, sizeof(Query), compare);

// Execute Mo's Algorithm
mo_algorithm();

// Output the answers for each query
printf("Query Results:\n");
for (int i = 0; i < q; i++) {
printf("Query %d: %d\n", i + 1, answer[i]);
}

return 0;
}
49 changes: 49 additions & 0 deletions 1D Arrays/Mo's Algorithm/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Mo's Algorithm for Efficient Range Queries

## Description

Mo's Algorithm is a powerful offline algorithm used to efficiently answer multiple range queries on a static array. It optimizes query processing by organizing overlapping range queries and reducing redundant calculations, making it particularly useful for datasets where frequent range queries need to be resolved without modifying the array.

## Key Features
- **Block Decomposition**: The array is divided into blocks of size √N, where N is the array length. This reduces redundant calculations by allowing queries in each block to share some computed values.
- **Query Optimization**: Queries are sorted based on block indices and processed in a specific order to maximize efficiency.
- **Efficient Range Queries**: Mo's Algorithm is versatile for various types of range queries, including sum, frequency, and XOR operations.

## Problem Definition

Given an array and multiple range queries, each asking for a specific calculation (e.g., sum or XOR) over a subarray, the goal is to answer each query as efficiently as possible.

- **Input**:
- An array of integers.
- Multiple range queries, each specifying a start and end index.
- **Output**: An efficient way to answer each query with reduced computation time.

## Algorithm Review

### 1. Initialization
- Divide the array into blocks of size √N, where N is the number of elements in the array.
- Sort the queries based on the block of their starting index (or both start and end indices if within the same block).

### 2. Query Processing
- Process each query by adjusting a current range of indices, only moving elements in or out of the range as needed:
- **Move Left or Right**: Adjust the range to the new query range.
- **Update Computation**: Recompute the necessary values, adding or removing elements as required.

### 3. Sorting and Efficiency
- Sorting the queries enables minimizing movement, which optimizes calculations as shared values can be reused.

## Complexity Analysis

- **Time Complexity**: O((N + Q) * √N), where N is the length of the array and Q is the number of queries.
- **Space Complexity**: O(N), for storing additional data structures and arrays.

## Applications

Mo's Algorithm is valuable in scenarios involving multiple range queries, such as:
- **Competitive Programming**: Optimizing repeated range queries on static arrays.
- **Data Analysis**: Quickly calculating aggregates (like sum or frequency) over specified ranges in datasets.
- **Image and Signal Processing**: For tasks that require overlapping range queries on static data.

## Conclusion

Mo's Algorithm is an efficient way to handle overlapping range queries on large datasets with static arrays. Its block decomposition and query ordering make it ideal for applications requiring numerous range queries where direct recomputation would be too slow. Understanding and implementing Mo's Algorithm enhances one’s ability to manage complex range queries efficiently in various fields, especially in competitive programming and data analysis.

0 comments on commit a71ed0c

Please sign in to comment.