Think about what we want to find. Ignore the i*i part. We have only
(L + (i - 1)) / i * i) to consider. (I wrote the L capital since l and 1 look quite similar)
What should it be? Obviously it should be the smallest number within L..R that is divisible by i. That's when we want to start to sieve out.
The last part of the formula, / i * i finds the next lower number that is divisible by i by using the properties of integer division.
Example: 35 div 4 * 4 = 8 * 4 = 32, 32 is the highest number that is (equal or) lower than 35 which is divisible by 4.
The L is where we want to start, obviously, and the + (i-1) makes sure that we don't find the highest number equal or lower than but the smallest number equal or bigger than L that is divisible by i.
Example: (459 + (4-1)) div 4 * 4 = 462 div 4 * 4 = 115 * 4 = 460.
460 >= 459, 460 | 4, smallest number with that property
(the max( i*i, ...) is only so that i is not sieved out itself if it is within L..R, I think, although I wonder why it's not 2 * i)
For reasons of readability, I'd made this an inline function next_divisible(number, divisor)
or the like. And I'd make it clear that integer division is used. If not, somebody clever might change it to regular division, with which it wouldn't work.
Also, I strongly recommend to wrap the array. It is not obvious to the outside that the property for a number X is stored at position X - L. Something like a class RangedArray
that does that shift for you, allowing you a direct input of X instead of X - L, could easily take the responsibility. If you don't do that, at least make it a vector, outside of a innermost class, you shouldn't use raw arrays in C++.