-
Notifications
You must be signed in to change notification settings - Fork 292
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 #1459 from divyalakshmi0/main
Added Mo's Algorithm for Efficient Range Queries
- Loading branch information
Showing
2 changed files
with
154 additions
and
0 deletions.
There are no files selected for viewing
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,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; | ||
} |
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,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. |