给定一个由N 个元素和Q 个查询组成的数组 arr ,由 L和R表示一个范围,任务是打印子数组 [L, R] 中奇偶校验元素的计数。
例子:
Input:
arr[]=[5, 2, 3, 1, 4, 8, 10]
Q=2
1 3
0 4
Output:
2 1
3 2
Explanation:
In query 1, odd parity elements in subarray [1:3] are 2 and 1 and even parity element is 3.
In query 2, odd parity elements in subarray [0:4] are 2, 1 and 4 and even parity elements are 5 and 3.
Input:
arr[] = { 13, 17, 12, 10, 18, 19, 15, 7, 9, 6 }
Q=3
1 5
0 7
2 9
Output:
1 4
3 5
2 6
Explanation:
In query 1, odd parity element in subarray [1:4] is 19 and even parity elements are 17,12,10 and 18.
In query 2, odd parity elements in subarray [0:7] are 13, 19 and 7 and even parity elements are 17,12,10,18 and 15.
In query 3, odd parity elements in subarray [2:6] are 19 and 7 and even parity elements are 12,10,18, 15, 9 and 6.
方法:
MO 算法的思想是对所有查询进行预处理,以便一个查询的结果可以在下一个查询中使用。
- 对所有查询进行排序,将L值从0 到 √n – 1的查询放在一起,然后是从√n 到 2×√n – 1 的查询,依此类推。块内的所有查询都按R值的升序排序。
- 计算奇校验元素,然后计算偶校验元素为(R-L+1-奇校验元素)
- 一一处理所有查询并增加奇校验元素的计数并将结果存储在结构中。
- 让count_oddP存储先前查询中奇数奇偶校验元素的计数。
- 删除先前查询的额外元素并为当前查询添加新元素。例如,如果之前的查询是 [0, 8] 而当前的查询是 [3, 9],那么移除元素 arr[0]、arr[1] 和 arr[2] 并添加 arr[9]。
- 为了显示结果,请按照提供的顺序对查询进行排序。
添加元素()
- 如果当前元素具有奇校验,则增加count_oddP的计数。
- 如果当前元素具有奇校验,则减少count_oddP的计数。
下面的代码是上述方法的实现:
C++
// C++ program to count odd and // even parity elements in subarray // using MO's algorithm #include
using namespace std; #define MAX 100000 // Variable to represent block size. // This is made global so compare() // of sort can use it. int block; // Structure to represent a query range struct Query { // Starting index int L; // Ending index int R; // Index of query int index; // Count of odd // parity elements int odd; // Count of even // parity elements int even; }; // To store the count of // odd parity elements int count_oddP; // Function used to sort all queries so that // all queries of the same block are arranged // together and within a block, queries are // sorted in increasing order of R values. bool compare(Query x, Query y) { // Different blocks, sort by block. if (x.L / block != y.L / block) return x.L / block < y.L / block; // Same block, sort by R value return x.R < y.R; } // Function used to sort all queries in order of their // index value so that results of queries can be printed // in same order as of input bool compare1(Query x, Query y) { return x.index < y.index; } // Function to Add elements // of current range void add(int currL, int a[]) { // _builtin_parity(x)returns true(1) // if the number has odd parity else // it returns false(0) for even parity. if (__builtin_parity(a[currL])) count_oddP++; } // Function to remove elements // of previous range void remove(int currR, int a[]) { // _builtin_parity(x)returns true(1) // if the number has odd parity else // it returns false(0) for even parity. if (__builtin_parity(a[currR])) count_oddP--; } // Function to generate the result of queries void queryResults(int a[], int n, Query q[], int m) { // Initialize number of odd parity // elements to 0 count_oddP = 0; // Find block size block = (int)sqrt(n); // Sort all queries so that queries of // same blocks are arranged together. sort(q, q + m, compare); // Initialize current L, current R and // current result int currL = 0, currR = 0; for (int i = 0; i < m; i++) { // L and R values of current range int L = q[i].L, R = q[i].R; // Add Elements of current range while (currR <= R) { add(currR, a); currR++; } while (currL > L) { add(currL - 1, a); currL--; } // Remove element of previous range while (currR > R + 1) { remove(currR - 1, a); currR--; } while (currL < L) { remove(currL, a); currL++; } q[i].odd = count_oddP; q[i].even = R - L + 1 - count_oddP; } } // Function to display the results of // queries in their initial order void printResults(Query q[], int m) { sort(q, q + m, compare1); for (int i = 0; i < m; i++) { cout << q[i].odd << " " << q[i].even << endl; } } // Driver Code int main() { int arr[] = { 5, 2, 3, 1, 4, 8, 10, 12 }; int n = sizeof(arr) / sizeof(arr[0]); Query q[] = { { 1, 3, 0, 0, 0 }, { 0, 4, 1, 0, 0 }, { 4, 7, 2, 0, 0 } }; int m = sizeof(q) / sizeof(q[0]); queryResults(arr, n, q, m); printResults(q, m); return 0; }
输出:2 1 3 2 2 2
时间复杂度: O(Q × √n)
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live
删除元素()
- 如果当前元素具有奇校验,则减少count_oddP的计数。