Поместите свои целые числа, начальные и конечные точки в один список пар. Сделайте для первого элемента каждой пары значение целого числа, начальной точки или конечной точки, а для второго элемента каждой пары - 0, -1 или 1, в зависимости от того, является ли это целое число, начальная точка или конечная точка.
Далее сортируйте список.
Теперь вы можете go просматривать список, сохраняя промежуточную сумму вторых элементов пар. Когда вы видите пару со вторым элементом 0, запишите промежуточную сумму (с отрицанием) для этого целого числа.
Это выполняется за O ((N + M) log (N + M)) в худшем случае ( и на практике я думаю, что это будет линейно, если запросы и интервалы будут в основном отсортированы, благодаря timsort).
Например:
Input intervals: [(1, 3), (5, 6), (6, 9)]
Input integers: [2, 4, 6, 8]
Unified list (sorted):
[(1,-1), (2,0), (3,1), (4,0), (5,-1), (6, -1), (6,0), (6,1), (8,0), (9,1)]
Running sum:
[-1 , -1, 0, 0, -1, -2, 0, -1, -1, 0]
Values for integers:
2: 1, 4: 0, 6: 2, 8, 1
Пример кода:
def query(qs, intervals):
xs = [(q, 0) for q in qs] + [(x, -1) for x, _ in intervals] + [(x, 1) for _, x in intervals]
S, r = 0, dict()
for v, s in sorted(xs):
if s == 0:
r[v] = S
S -= s
return r
intervals = [(3, 3), (22, 30), (17, 29), (7, 12), (12, 34), (18, 38), (30, 40), (5, 27), (19, 26), (27, 27), (1, 31), (17, 17), (22, 25), (6, 14), (5, 7), (9, 19), (24, 28), (19, 40), (9, 36), (2, 32)]
queries = [16, 18, 39, 40, 27, 28, 4, 23, 15, 24, 2, 6, 32, 17, 21, 29, 31, 7, 20, 10]
print(query(queries, intervals))
Вывод:
{2: 2, 4: 2, 6: 5, 7: 6, 10: 7, 15: 6, 16: 6, 17: 8, 18: 8, 20: 9, 21: 9, 23: 11, 24: 12, 27: 11, 28: 9, 29: 8, 31: 7, 32: 6, 39: 2, 40: 2}