XOR After Range Multiplication Queries II

Hard
Watch on YouTube ↗

Solution

class Solution {

    static final int MOD = 1_000_000_007;

    int power(long base, long exp) {
        long ans = 1;
        while(exp > 0) {
            if((exp & 1) == 1) ans = (ans * base) % MOD;
            base = (base * base) % MOD;
            exp >>= 1;
        }
        return (int) ans;
    }

    public int xorAfterQueries(int[] nums, int[][] queries) {
        int n = nums.length;
        int k = (int) Math.sqrt(n);

        List<List<int[]>> blocks = new ArrayList<>(); 
        for(int i = 0; i < k; i++) blocks.add(new ArrayList<>());

        for(int[] q : queries) {
            int l = q[0], r = q[1], step = q[2], val = q[3];  
            if(step < k) {
                blocks.get(step).add(new int[]{l, r, val});
            } else {
                while(l <= r) {
                    nums[l] = (int)(((long) nums[l] * val) % MOD);  
                    l += step;  
                }
            }
        }

        long[] mul = new long[n];

        for(int step = 1; step < k; step++) {
            if(blocks.get(step).isEmpty()) continue;
            Arrays.fill(mul, 1);

            for(int[] q : blocks.get(step)) {
                int l = q[0], r = q[1], val = q[2];
                mul[l] = (mul[l] * val) % MOD;
                int end = l + ((r - l) / step + 1) * step;
                if(end < n)
                    mul[end] = (mul[end] * power(val, MOD - 2)) % MOD;
            }

            for(int i = step; i < n; i++)
                mul[i] = (mul[i] * mul[i - step]) % MOD;

            for(int i = 0; i < n; i++)
                nums[i] = (int)(((long) nums[i] * mul[i]) % MOD);  
        }

        int ans = 0;
        for(int num : nums) ans ^= num;
        return ans;
    }
}