Below is the implementation of MO algorithm for summing the sub array given the range as input. As MO algorithm is a offline query it is given a list of ranges as input.
Below code calculates the result using MO algorithm and compares the result with expected output by directly summing the sub array.
MO algorithm first divides the whole array in sqrt(len of array)
blocks and then divides the queries based on blocks. It sorts the input queries based on blocks and then based on the right parameters if the block number is same. It uses two pointers which moves left and right based on input query. The main intention of the algorithm is to reduce the movements of the pointers.
import collections
import math
def cmp(a, b):
if a > b:
return 1
elif a < b:
return -1
return 0
def compare(a, b):
def bin(x):
return x[0]/r
result = cmp(a, b)
if result:
return result
return cmp(x[1], y[1])
a = [1, 1, 2, 1, 3, 4, 5, 2, 8];
r = math.sqrt(len(a))
d_query = {0:[0, 5], 1:[5, 8], 2:[2, 4], 3:[5, 6]}
od = collections.OrderedDict(sorted(d_query.items(), compare, key= lambda x: x[1]))
print(od)
l = r = 0
cur_sum = 0
cur_l = 0
cur_r = -1
result = {}
for key, value in od.items():
l = value[0]
r = value[1]
while cur_r < r:
cur_r += 1
cur_sum += a[cur_r]
while cur_r > r:
cur_sum -= a[cur_r]
cur_r -= 1
while cur_l < l:
cur_sum -= a[cur_l]
cur_l += 1
while cur_l > l:
cur_l -= 1
cur_sum += a[cur_l]
result[key] = cur_sum
for (k1,v1), (k2, v2) in zip(d_query.items(),result.items()):
if k1 != k2 or v1 == v2:
print("failed")
break
print(result)