Multi-Colored Segments (Codeforces 1741F)
Tags: Math, sortings

Dmitry has $$$n$$$ segments of different colors on the coordinate axis $$$Ox$$$. Each segment is characterized by three integers $$$l_i$$$, $$$r_i$$$ and $$$c_i$$$ ($$$1 \le l_i \le r_i \le 10^9, 1 \le c_i \le n$$$), where $$$l_i$$$ and $$$r_i$$$ are are the coordinates of the ends of the $$$i$$$-th segment, and $$$c_i$$$ is its color.Dmitry likes to find the minimum distances between segments. However, he considers pairs of segments of the same color uninteresting. Therefore, he wants to know for each segment the distance from this segment to the nearest differently colored segment.The distance between two segments is the minimum of the distances between a point of the first segment and a point of the second segment. In particular, if the segments intersect, then the distance between them is equal to $$$0$$$.For example, Dmitry has $$$5$$$ segments:    The first segment intersects with the second (and these are segments of different colors), so the answers for them are equal to $$$0$$$.  For the $$$3$$$-rd segment, the nearest segment of a different color is the $$$2$$$-nd segment, the distance to which is equal to $$$2$$$.  For the $$$4$$$-th segment, the nearest segment of a different color is the $$$5$$$-th segment, the distance to which is equal to $$$1$$$.  The $$$5$$$-th segment lies inside the $$$2$$$-nd segment (and these are segments of different colors), so the answers for them are equal to $$$0$$$. 

Input: The first line of the input contains an integer $$$t$$$ ($$$1 \le t \le 10^4$$$) — the number of test cases in the test.The descriptions of the test cases follow.The first line of description of each test case contains one integer $$$n$$$ ($$$2 \le n \le 2 \cdot 10^5$$$) — the number of segments.The next $$$n$$$ lines contain descriptions of the segments. Each segment is described by three integers $$$l_i$$$, $$$r_i$$$ and $$$c_i$$$ ($$$1 \le l_i \le r_i \le 10^9, 1 \le c_i \le n$$$) — coordinates of the left and right ends of $$$i$$$-th segment, as well as the color of this segment. It is guaranteed that there are at least $$$2$$$ segments of different colors.It is guaranteed that the sum of $$$n$$$ over all test cases does not exceed $$$2 \cdot 10^5$$$.

Output: For each test case, on a separate line print $$$n$$$ integers, where the $$$i$$$-th number is equal to the distance from the $$$i$$$-th segment to the nearest segment of a different color.

Note: In the first test case of the first sample there is only one segment of color $$$2$$$, and all other segments have color $$$1$$$. Therefore, for segments of color $$$1$$$, the answer is equal to the distance to the $$$3$$$rd segment, and for $$$3$$$rd one, the answer is equal to the minimum of the distances to segments of color $$$1$$$.In the second test case of the first sample there are only $$$2$$$ segments, and for both of them the answer is equal to the distance between them.In the third test case of the first sample, each segment intersects at least one of its ends with a segment of a different color, so all answers are equal to $$$0$$$.The fourth test case of the first sample is described in the problem statement.In the fifth test case of the first sample, one segment lies completely inside the other, and for both of them the answer is $$$0$$$.In the sixth test case of the first sample, all segments are points of different colors.

Sample Inputs:
9
3
1 2 1
3 4 1
5 6 2
2
100000000 200000000 1
900000000 1000000000 2
5
1 2 1
2 3 2
3 4 3
4 5 4
5 6 5
5
1 5 1
4 9 2
1 2 1
8 9 2
5 7 3
2
1 100 2
10 90 1
3
1 1 1
10 10 2
1000000000 1000000000 3
3
3 4 1
2 5 1
1 6 2
6
5 6 2
11 12 3
7 8 2
3 4 2
1 2 1
9 10 2
2
1 3 1
2 3 2

4
8
11 16 7
12 15 7
2 5 8
17 22 5
1 8 8
19 23 8
16 16 6
6 7 5
9
1 4 3
5 11 1
8 11 3
1 10 1
2 11 1
1 10 4
3 11 1
5 7 1
1 11 1
9
25 25 1
26 26 1
24 24 2
13 14 2
12 16 2
17 18 1
19 19 1
24 27 2
24 27 1
9
15 18 1
20 22 2
13 22 2
13 22 2
3 13 2
6 10 2
3 6 2
19 24 2
22 24 2

Sample Outputs:
3 1 1 
700000000 700000000 
0 0 0 0 0 
0 0 2 1 0 
0 0 
9 9 999999990 
0 0 0 
3 1 3 1 1 1 
0 0

0 1 1 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 3 1 1 3 0 0 
0 2 0 0 2 5 9 1 4

Solution (Python):
from functools import lru_cache as cache
from collections import Counter, defaultdict, deque
import math
import bisect
import string
from heapq import *
import sys

def get_int():
    return int(input())

def get_ints():
    return map(int, sys.stdin.readline().strip().split())

def get_list():
    return list(map(int, sys.stdin.readline().strip().split()))

def get_str():
    return sys.stdin.readline().strip()

def main():
    testcases = get_int()
    for _ in range(testcases):
        n = get_int()
        intervals = []
        for _ in range(n):
            (l, r, c) = get_ints()
            intervals.append((l, r, c))
        print(solve(n, intervals))

def solve(n, intervals):
    result = [math.inf for i in range(n)]
    test = []
    intervals = sorted([(l, r, c, i) for (i, (l, r, c)) in enumerate(intervals)])
    seen = [[-1, -1], [-2, -1]]
    for (l, r, c, i) in intervals:
        if seen[0][1] != -1 and seen[0][1] != c:
            result[i] = min(result[i], max(0, l - seen[0][0]))
        if seen[1][1] != -1 and seen[1][1] != c:
            result[i] = min(result[i], max(0, l - seen[1][0]))
        if seen[0][1] == c:
            seen[0][0] = max(seen[0][0], r)
        elif seen[1][1] == c:
            seen[1][0] = max(seen[1][0], r)
        elif seen[0][0] <= seen[1][0] and seen[0][0] < r:
            seen[0] = [r, c]
        elif seen[0][0] > seen[1][0] and seen[1][0] < r:
            seen[1] = [r, c]
    seen = [[10 ** 10, -1], [10 ** 11, -1]]
    for (l, r, c, i) in reversed(intervals):
        if seen[0][1] != -1 and seen[0][1] != c:
            result[i] = min(result[i], max(0, seen[0][0] - r))
        if seen[1][1] != -1 and seen[1][1] != c:
            result[i] = min(result[i], max(0, seen[1][0] - r))
        if seen[0][1] == c:
            seen[0][0] = min(seen[0][0], l)
        elif seen[1][1] == c:
            seen[1][0] = min(seen[1][0], l)
        elif seen[0][0] >= seen[1][0] and seen[0][0] > l:
            seen[0] = [l, c]
        elif seen[0][0] < seen[1][0] and seen[1][0] > l:
            seen[1] = [l, c]
    return ' '.join(map(str, result))
if __name__ == '__main__':
    main()

Solution (Python):
from functools import lru_cache as cache
from collections import Counter, defaultdict, deque
import math
import bisect
import string
from heapq import *
import sys

def get_int():
    return int(input())

def get_ints():
    return map(int, sys.stdin.readline().strip().split())

def get_list():
    return list(map(int, sys.stdin.readline().strip().split()))

def get_str():
    return sys.stdin.readline().strip()

def main():
    testcases = get_int()
    for _ in range(testcases):
        n = get_int()
        intervals = []
        for _ in range(n):
            (l, r, c) = get_ints()
            intervals.append((l, r, c))
        print(solve(n, intervals))

def solve(n, intervals):
    result = [math.inf for i in range(n)]
    test = []
    intervals = sorted([(l, r, c, i) for (i, (l, r, c)) in enumerate(intervals)])
    seen = [[-1, -1], [-2, -1]]
    for (l, r, c, i) in intervals:
        if seen[0][1] != -1 and seen[0][1] != c:
            result[i] = min(result[i], max(0, l - seen[0][0]))
        if seen[1][1] != -1 and seen[1][1] != c:
            result[i] = min(result[i], max(0, l - seen[1][0]))
        if seen[0][1] == c:
            seen[0][0] = max(seen[0][0], r)
        elif seen[1][1] == c:
            seen[1][0] = max(seen[1][0], r)
        elif seen[0][0] <= seen[1][0] and seen[0][0] < r:
            seen[0] = [r, c]
        elif seen[0][0] > seen[1][0] and seen[1][0] < r:
            seen[1] = [r, c]
    seen = [[10 ** 10, -1], [10 ** 11, -1]]
    for (l, r, c, i) in reversed(intervals):
        if seen[0][1] != -1 and seen[0][1] != c:
            result[i] = min(result[i], max(0, seen[0][0] - r))
        if seen[1][1] != -1 and seen[1][1] != c:
            result[i] = min(result[i], max(0, seen[1][0] - r))
        if seen[0][1] == c:
            seen[0][0] = min(seen[0][0], l)
        elif seen[1][1] == c:
            seen[1][0] = min(seen[1][0], l)
        elif seen[0][0] >= seen[1][0] and seen[0][0] > l:
            seen[0] = [l, c]
        elif seen[0][0] < seen[1][0] and seen[1][0] > l:
            seen[1] = [l, c]
    return ' '.join(map(str, result))
if __name__ == '__main__':
    main()

Solution (Python):
t = int(input())
out = ''
for _ in range(t):
    n = int(input())
    segs = []
    for i in range(n):
        segs.append([int(x) - 1 for x in input().split()])
        segs[-1].append(i)
    segs.sort()
    sg = []
    last = -1
    for x in segs:
        if x[-2] != last:
            sg.append([])
            last = x[-2]
        sg[-1].append(x)
    ans = [float('inf')] * n
    e = 0
    c = sg[0][0][-2]
    for x in sg[0]:
        ans[x[-1]] = max(0, sg[1][0][0] - x[1])
        e = max(e, x[1])
    e2 = 0
    c2 = sg[1][0][-2]
    for x in sg[1]:
        if len(sg) > 2:
            ans[x[-1]] = max(0, sg[2][0][0] - x[1])
        ans[x[-1]] = min(ans[x[-1]], max(0, x[0] - e))
        e2 = max(e2, x[1])
    for i in range(1, len(sg)):
        te = sg[i][0][1]
        for x in sg[i]:
            if c != x[-2]:
                ans[x[-1]] = max(0, x[0] - e)
            else:
                ans[x[-1]] = max(0, x[0] - e2)
            if i < len(sg) - 1:
                ans[x[-1]] = min(ans[x[-1]], max(0, sg[i + 1][0][0] - x[1]))
            te = max(te, x[1])
        if te > e:
            if sg[i][0][-2] == c:
                e = te
            else:
                e2 = e
                c2 = c
                e = te
                c = sg[i][0][-2]
        elif te > e2 and sg[i][0][-2] != c:
            e2 = te
            c2 = sg[i][0][-2]
    for x in ans:
        out += str(x) + ' '
    out += '\n'
print(out)