Problem Statement
Given an integer array A of size N, handle Q queries of the following types:
- (0, l, r, x): Replace all the elements in the subarray A[l],[l + 1]......A[r - 1],A[r] with x.
- (1, l, r, x): Increment all the elements in the subarray A[l],[l + 1]......A[r - 1],A[r] by x.
- (2, l, r): Calculate sum of squares of elements in the subarray A[l],[l + 1]......A[r - 1],A[r].
Constraints
1 <= N, Q <= 5e5
1 <= l , r <= N
1 <= x <= 1e6
Sample Test Cases
Input: 8 5
1 2 3 4 5 6 7 8
2 1 3
0 1 4 4
2 1 3
1 1 8 1
2 1 5
Output: 14
48
136
Explanation: Initially, A = {1, 2, 3, 4, 5, 6, 7, 8}
Query1: The sum of squares of all the elements in the range [1, 3] = 1 * 1 + 2 * 2 + 3 * 3 = 1 + 4 + 9 = 14.
Query2: Replace all the elements in the range [1, 4] with 4,
A = {4, 4, 4, 4, 5, 6, 7, 8}
Query3: The sum of squares of all the elements in the range [1, 3] = 4 * 4 + 4 * 4 + 4 * 4 = 16 + 16 + 16 = 48.
Query4: Increment all the elements in the range [1, 8] by 1,
A = {5, 5, 5, 5, 6, 7, 8, 8}
Query5: The sum of squares of all the elements in the range [1, 8] = 5 * 5 + 5 * 5 + 5 * 5 + 5 * 5 + 6 * 6 = 25 + 25 + 25 + 25 + 36 = 136.
Also see, Euclid GCD Algorithm
Approach
We can solve this problem efficiently using the segment tree with lazy propagation.
To answer the query, we will maintain a segment tree that stores the sum of squares in a range, and to perform the update, along with the lazy tree, we need another segment tree that will store the sum of elements in a range.
Instead of creating two segment trees, we can create one that will store two variables, the 'sum' (to store the sum) and the 'sumOfSquare' (to store the sum of squares).
How to perform the update in the range [l, r]??
To update all the elements lying in the range [l, r], we will start from the root node and recursively update the nodes in the following way -
Suppose [cl, cr] be the range of the current node. Now there are 3 cases:
- cr < l or cl > r: The current node is out of range, so there is no need to update it or its children.
- cl >= l and cr <= r: The current node lies entirely inside the range [l, r], so update it and postpone the update of its children using the lazy tree.
- (cl < l and cr <= r) or (cl >= l and cr > r): The current node overlaps partially. So recursively update its children first then update it.
In the case of the first type of update (0, l, r, x):
The updated sum is ,
sum = a[l] + a[l + 1] + ..... + a[r - 1] + a[r]
= x + x + ... + x
= (cr - cl + 1) * x
and the updated sum of square is,
sumOfsquare = a[l] * a[l] + a[l + 1] * a[l + 1] + ..... + a[r - 1] * a[r - 1] + a[r] * a[r]
= x * x + x * x + ......+ x * x + x * x
= (r - l + 1) * x * x
And,
In the case of the second type of update (1, l, r, x):
The updated sum is ,
sum = (a[l] + x) + (a[l + 1] + x) + ..... + (a[r - 1] + x) + (a[r] + x)
= (a[l] + a[l + 1] + ..... + a[r - 1] + a[r]) + (x + x + .... + x + x)
= sum + (r - l + 1) * x
and the updated sum of square is,
sumOfsquare = (a[l] + x)^2 + (a[l + 1] + x)^2 + + ..... + (a[r - 1] + x)^2 + (a[r] + x)^2
using the formula (p + q)^2 = p^2 + q^2 + 2 * p * q
sumOfsquare = a[l] * a[l] + a[l + 1] * a[l + 1] + ........ + a[r - 1] * a[r] + (x * x + x * x + ...... + x * x + x * x) + 2 * x * (a[l] + a[l + 1] + .... ... + a[r - 1] + a[r])
sumOfsquare = sumOfsquare + (r - l + 1) * x * x + 2 * x * sum
How to postpone the updates using the lazy tree??
Every node in the lazy tree stores two values, 'type' and 'val'. type = -1 indicates that there is no pending update, type = 0 indicates pending update of type (0, l, r, x), and type = 1 indicates pending update of type (1, l, r, x).
Suppose lazy[] be an array used to store the lazy tree and node be the current node.
If the pending update at the current node (node) is of type 1, then perform the update using the above formulas and push the update to the children (i.e., set lazy[2 * node + 1] = lazy[node] and lazy[2 * node + 2] = lazy[node]).
If the update is of type 2, then update the current node using the above formulas. And to push the update to the children, there are two cases -
- If there is no pending update (i.e lazy[2 * node + 1].type == -1): postpone the update at the current node to its children.
- If there is a pending update (i.e lazy[2 * node + 1].type == 0 or lazy[2 * node + 1].type == 1): increment the val of children by val of the current node.