 # SEGPROD - Editorial

Author: Denis Anischenko
Tester: Istvan Nagy
Editorialist: Oleksandr Kulkov

MEDIUM-HARD

### PREREQUISITES:

None (though knowledge of sparse table may be helpful for understanding)

### PROBLEM:

Given a non-changing array, answer queries of the form “? l r: what is \prod\limits_{i=l}^{r} a_i modulo P (P is not necessarily prime)?” (subarray product query). The queries are online, and the constraints are so tight that an O(1) per query solution is required.

### QUICK EXPLANATION:

The intended solution does not utilize the fact that the query operation is product modulo P. The proposed data structure is capable of handling any associative operation query on subarray in O(1) (online, provided that the array is not changing).

The idea of the intended data structured is somewhat similar to the idea of a sparse table: we will precompute the operation results on some subarrays of the array so that every input query subarray can be represented as a union of constant (at most 2) number of subarrays we already know the answer for. However, the difference with the classic sparse table (used for static RMQ problem) is that the given operation \bigoplus is not idemptotent: a\bigoplus a\neq a for the most of a's, so the union we will use must be disjoint. The operation is also not invertible, so we can’t use the prefix-sums approach.

For each k=1,\ldots,\lceil \log_2 N\rceil consider all indices of the array that are divisible by 2^k as “pivots”. Precompute the product on subarrays whose left or right bound is a “pivot”, and that do not contain any other pivots.

Claim: for each [l,r] query we can choose pivot element 2^k\cdot x in such way that we already precomputed the operation for some subarray with indices [l, 2^k\cdot x), [2^k\cdot x, r].

### EXPLANATION:

Build the following data structure: for each k=1,\ldots,\lceil \log_2 N\rceil, for each i=0,1,\ldots,N-1 (we use 0-indexation of the array) compute (we omit modulo P for simplicity; assume that all integers are members of the ring \mathbb{Z}_P, with multiplication defined accordingly):

A_{k,i}=\prod\limits_j a_j\text{ for }\left\lfloor\dfrac{i}{2^k}\right\rfloor\cdot 2^k\le j\le i

B_{k,i}=\prod\limits_j a_j \text{ for }i\le j \le \left\lceil\dfrac{i+1}{2^k}\right\rceil\cdot 2^k-1

Here \text{~} denotes bitwise negation, \& denotes bitwise AND operation.

The meaning of the expressions is the following:

1. \left\lfloor\dfrac{i}{2^k}\right\rfloor\cdot 2^k is the largest number not exceeding i that is divisible by 2^k. Implementation-wise, this number I is characterized by the property I~\&~ 2^k=0 (\& denotes bitwise AND).

2. \left\lceil\dfrac{i+1}{2^k}\right\rceil\cdot 2^k-1 is by one less than the smallest number more than i that is divisible by 2^k. Implementation-wise, this number J is characterized by the property J\& 2^k=2^k-1 (\& denotes bitwise AND).

Let’s notice the following: suppose we have a query [L, R], L\neq R, and for selected k the range of indices [L+1, R] contains unique index I divisible by 2^k. Then

B_{k,L}\cdot A_{k,R}=\prod_{i=L}^R a_i

Indeed, if that index of the form I=2^k\cdot x\in[L+1, R] exists and is unique, then, by the meaning of the corresponding expressions above:

I=\left\lfloor\dfrac{R}{2^k}\right\rfloor\cdot 2^k

I=\left\lceil\dfrac{L+1}{2^k}\right\rceil\cdot 2^k

And by definition of B_{k,L} and A_{k,R}:

B_{k,L}\cdot A_{k,R}=\prod_{j=L}^I a_j \cdot \prod_{j=I-1}^R a_j=\prod_{j=L}^R a_j

Can we find the k for which I is unique? Surely, such k exists because if for some k there are X>1 indices divisible by 2^k in the range [L+1,R], for k+1 there are \dfrac{X}{2} such indices if X is even and either \left\lfloor\dfrac{X}{2}\right\rfloor or \left\lceil\dfrac{X}{2}\right\rceil if X is odd. Incrementing k sufficient number of times we arrive to X=1.

It remains to notice that k can be chosen as k=\max\limits_l: 2^l\le L\oplus R (\oplus denotes bitwise XOR).

### AUTHOR’S AND TESTER’S SOLUTIONS:

Author’s solution can be found here.

Tester’s solution can be found here.

### RELATED PROBLEMS:

6 Likes

If you think of the array as a tree (chain), this is similar to centroid decomposition. Dividing the array(tree) into O(NlogN) subarrays(paths), in a way that any subarray can be represented as a concatenation of two of those O(NlogN) subarrays. If we append 1’s to the array until its size becomes 2^k-1 and then perform the decomposition, the nodes at height ‘h’ will have 2^(k-1-h), (assuming root is at height 0) as the largest power of 2 that divides them. The LCA of two nodes l,r will be some number l<=i<=r of the form x*2^k as mentioned in the editorial. We need to decrease ‘r’ until it becomes a multiple of some power of 2 having power as large as possible. This is same as picking a ‘1’ in 'r’s binary representation and setting all bits to the right of it to ‘0’. But, the ‘1’ we pick cannot be to the left of the first point of difference in the binary representations of l,r, because then ‘r’ would become less than ‘l’. That is exactly what the largest set bit in (l XOR r) represents.

For example- Consider array of size 15, then 8 is the root with children 4 and 12 and so on. Consider the query from 5 to 7 and we get the required number by which splitting is done as 6. (their lca). Similar is the case with query 7 and 11 and lca as 8.

9 Likes

can anyone give me the easy explaination as i am not understanding the editorial…

1 Like

@soumik33
See here,we precompute the prefix product for all indices which are divisible by 2^k where k=1…logN
So

We calulate prefix product for all subarrays from prevPivot+1 to currPrivot-1. And prefix product from currPivot to nextpivot - 1

So lets say for k=2:
Indices:4,8,12,16,20,…
So we calculate for following ranges:
(1,3),(2,3),(3,3)
(4,4),(4,5),(4,6),(4,7)

(5,7),(6,7),(7,7)
(8,8),(8,9),(8,10),(8,11)

We do this for k=1…logN
Now suppose a query:
1-6
(Here pivot are 2,4)
So it can be (1-1)(2-3)(4-6)

(Here pivot is 4)
Or (1-3)*(4-6)
The second one takes only 1 multiplication

Consider another eg:
Range 17:22
So (17:19)*(20:22)

Since we have precalculated for these results for all multiples of power of 2 it can be done in O(1).
#note 20=4 * 5=(2^2)*5

So it means we have to choose such a number in the range which is multiple of some 2^k and k is maximum(as if not we have to do more than 1 multiplication)

So lets express 17:0b10001
22:10110
Exor result=111
So last set bit is 2
So pivot is multiple of 2^2

(Also note that there is only 1 multiple x for x*2^k as for x-1 it is less than L and for x+1 it is greater than R)

Proof for xor:
See @hemanth_1 comment.Really nice explaination.

Hope this helps.
Plz correct me if i am wrong.

1 Like

In the editorial, there have been defined two numbers I and J with the properties:
I&(2^k) =0 and j&(2^k) = 2^k-1 , can anyone give some examples by taking values of I , J and k to illustrate this property.
Also in the Author’s solution , Some different property is being used which seems to be fine

@gagan86nagpal

It is same as i discussed in my comment.
They have used to arrays
A,B(2d arrays)

A(k,i) denotes product of all elements from largest value of 2^k * x (less than or equal to i) to i.So that value is floor(i/(2^k)) * 2^k
(consider for i=5 ,k=2 so val=4,

for i=8,k=2. Val=8)

B(k,i) denotes product of all elements from i to (smallest value of 2^k * x which is just greater than i) - 1.That value is ceil((i+1)/2^k)*2^k
(Consider i=5 k=2 so val=8 - 1=7

Consider i=8,k=2. So val=12 - 1 =11)

So as i said in prev comment :
For k=2 and for i=4…N
//for sake of confusion not considering from 1 (as 0 doesnt comes(1 based))

A(k,i)= [ (4,4), (4,5) , (4,6) , (4,7) , (8,8) , (8,9) ,…]

B(k,i)= [ (4,7) , (5,7) , (6,7) , (7,7) , (8,11) , (9,11) ,…]

Hope this helps.

Plz correct me if i am wrong.

1 Like

If anyone is finding the explanation a bit difficult to comprehend try this one

1 Like

Can somebody explain me how to do the pre computation (calculating A[][] and B[][]) . In sparse tables we have do simple dP to pre compute values . What can be done in this case . Is there any DP solution. Please Help?

@dheeraj21
I dont think any dp solution is required for this since k is only logN

Even with bruteforce you can do precomputation with complexity NlogN

Just travese array logN times.
(Note: for constructing A traverse from left to right , and for B right to left)

Hope this helps.Correct me if i am wrong.

I had a question. Do we require some awards for replying a comment? As there’s no option for replying to a particular comment.Due to this ,I always have to tag/mention that person.
Plz if some1 could explain this.

1 Like

can anyone please explain me a bit more how we are choosing k and x here ?

Is there any video tutorial for the same ?

In which we first solve the queries regarding the subarrays only of size 2^j where j varies from 0.1…log2(n).
Then for every corresponding subarray size starting from 1.2…4…8…16… we build our SPARSE TABLE in an bottom up dp approach within a O(nlogn) time.

Then for every query we check two things:

• First if the query size is divisible by 2 we can just look up from our sparse table
• otherwise we have to calculate the highest closest power of 2 to our query size by using int j = floor(log2(Ri-Li+1)). And then for the last subarray of size 2^j starting from R-(2^j)+1 till R we check our ans and also for the first subarray from L to (L+(2^j)-1) we find our answer …

Can anyone please tell me that can we apply this approach here as i know this approach works well for the range min, range max, range gcd type queries etc but for the range prod queries how to handle the ans for the 2 subarrays as discussed above when the size of query is not an power of 2.

nice explanation!

1 Like

Hi vivek_1998299, I want to make this clear enough.
Let’s say we want to find I for (14,17)
14: 0b001110
17: 0b010001
XOR: 0b011111, HEre last bit set is at 4, hence 2^4 i.e. 16.
Am i correct ?

What a great explanation man , thanks a ton!!

1 Like

Yes correct

Thanks for helping mate.I got the logic now , seems trivial now I can reply and I have 66 reputations while you have 12.
Maybe you are not under some “threshold” mate.

Along with brute force, Properties mentioned in “Explanation” section are heavily used. See the tester solution for more details.
Also, you can go through my code which is quite similar to Tester’s solution and have comments in it.