Minimum Array (Codeforces 1888F)
Tags: Math, binary search

Given an array $$$a$$$ of length $$$n$$$ consisting of integers. Then the following operation is sequentially applied to it $$$q$$$ times: Choose indices $$$l$$$ and $$$r$$$ ($$$1 \le l \le r \le n$$$) and an integer $$$x$$$; Add $$$x$$$ to all elements of the array $$$a$$$ in the segment $$$[l, r]$$$. More formally, assign $$$a_i := a_i + x$$$ for all $$$l \le i \le r$$$.Let $$$b_j$$$ be the array $$$a$$$ obtained after applying the first $$$j$$$ operations ($$$0 \le j \le q$$$). Note that $$$b_0$$$ is the array $$$a$$$ before applying any operations.You need to find the lexicographically minimum$$$^{\dagger}$$$ array among all arrays $$$b_j$$$.$$$^{\dagger}$$$An array $$$x$$$ is lexicographically smaller than array $$$y$$$ if there is an index $$$i$$$ such that $$$x_i < y_i$$$, and $$$x_j = y_j$$$ for all $$$j < i$$$. In other words, for the first index $$$i$$$ where the arrays differ, $$$x_i < y_i$$$.

Input: Each test consists of multiple test cases. The first line contains a single integer $$$t$$$ ($$$1 \le t \le 5 \cdot 10^5$$$) — the number of test cases. The description of the test cases follows.The first line of each test case contains a single integer $$$n$$$ ($$$1 \le n \le 5 \cdot 10^5$$$) — the length of array $$$a$$$.The second line of each test case contains $$$n$$$ integers $$$a_1, a_2, \ldots, a_n$$$ ($$$-10^9 \le a_i \le 10^9$$$) — the elements of array $$$a$$$.The third line of each test case contains a single integer $$$q$$$ ($$$0 \le q \le 5 \cdot 10^5$$$) — the number of operations on the array.In each of the next $$$q$$$ lines, there are three integers $$$l_j$$$, $$$r_j$$$, and $$$x_j$$$ $$$(1 \le l_j \le r_j \le n, -10^9 \le x_j \le 10^9)$$$ — the description of each operation. The operations are given in the order they are applied.It is guaranteed that the sum of $$$n$$$ over all test cases and the sum of $$$q$$$ over all test cases do not exceed $$$5 \cdot 10^5$$$.

Output: For each test case, output the lexicographically minimum array among all arrays $$$b_j$$$.

Note: In the first test case: $$$b_0 = [1,2,3,4]$$$; $$$b_1 = [1,2,3,4]$$$; $$$b_2 = [-99,-98,-97,4]$$$.Thus, the lexicographically minimum array is $$$b_2$$$.In the second test case, the lexicographically minimum array is $$$b_0$$$.

Sample Inputs:
2
4
1 2 3 4
2
1 4 0
1 3 -100
5
2 1 2 5 4
3
2 4 3
2 5 -2
1 3 1

Sample Outputs:
-99 -98 -97 4 
2 1 2 5 4

Solution (Python):
import heapq
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
t_num = int(input())
for _ in range(t_num):
    n = int(input())
    arr = list(map(int, input().split()))
    q = int(input())
    s = []
    e = []
    val = []
    heap = []
    d = {}
    for __ in range(q):
        (ss, se, sval) = list(map(int, input().split()))
        s.append(ss - 1)
        e.append(se)
        val.append(sval)
    ma = 0
    i = 0
    for (ss, se, sval) in zip(s, e, val):
        i += 1
        if ss not in d:
            d[ss] = 0
        if se not in d:
            d[se] = 0
        d[ss] += sval
        d[se] -= sval
        heapq.heappush(heap, ss)
        heapq.heappush(heap, se)
        while len(heap) > 0 and d[heap[0]] == 0:
            heapq.heappop(heap)
        if len(heap) > 0 and d[heap[0]] < 0:
            ma = i
            heap = []
            d = {}
    tarr = [0] * n
    for j in range(ma):
        ss = s[j]
        se = e[j]
        sval = val[j]
        tarr[ss] += sval
        if se < n:
            tarr[se] -= sval
    p = 0
    rarr = []
    for i in range(n):
        p += tarr[i]
        rarr.append(arr[i] + p)
    print(*rarr)

Solution (Python):
import io, os
import heapq
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

def main(t):
    n = int(input())
    arr = list(map(int, input().split()))
    q = int(input())
    change = []
    dic = {}
    heap = []
    minindex = -1
    for i in range(q):
        (l, r, diff) = map(int, input().split())
        l -= 1
        change.append((l, r, diff))
        if l not in dic:
            dic[l] = 0
        dic[l] += diff
        if r not in dic:
            dic[r] = 0
        dic[r] -= diff
        if dic[l] == 0:
            del dic[l]
        if dic[r] == 0:
            del dic[r]
        heapq.heappush(heap, l)
        heapq.heappush(heap, r)
        if diff < 0:
            while heap and heap[0] not in dic:
                heapq.heappop(heap)
            if len(heap) > 0 and dic[heap[0]] < 0:
                minindex = i
                dic.clear()
                heap = []
    ans = [0] * (n + 1)
    for i in range(minindex + 1):
        (l, r, diff) = (change[i][0], change[i][1], change[i][2])
        ans[l] += diff
        ans[r] -= diff
    for j in range(1, n):
        ans[j] += ans[j - 1]
    for j in range(n):
        ans[j] += arr[j]
    ans.pop()
    print(*ans)
T = int(input())
t = 1
while t <= T:
    main(t)
    t += 1

Solution (Python):
import sys
input = sys.stdin.readline
K = 10 ** 12

class SortedList:

    def __init__(self, iterable=[], _load=200):
        """"""
        values = sorted(iterable)
        self._len = _len = len(values)
        self._load = _load
        self._lists = _lists = [values[i:i + _load] for i in range(0, _len, _load)]
        self._list_lens = [len(_list) for _list in _lists]
        self._mins = [_list[0] for _list in _lists]
        self._fen_tree = []
        self._rebuild = True

    def _fen_build(self):
        """"""
        self._fen_tree[:] = self._list_lens
        _fen_tree = self._fen_tree
        for i in range(len(_fen_tree)):
            if i | i + 1 < len(_fen_tree):
                _fen_tree[i | i + 1] += _fen_tree[i]
        self._rebuild = False

    def _fen_update(self, index, value):
        """"""
        if not self._rebuild:
            _fen_tree = self._fen_tree
            while index < len(_fen_tree):
                _fen_tree[index] += value
                index |= index + 1

    def _fen_query(self, end):
        """"""
        if self._rebuild:
            self._fen_build()
        _fen_tree = self._fen_tree
        x = 0
        while end:
            x += _fen_tree[end - 1]
            end &= end - 1
        return x

    def _fen_findkth(self, k):
        """"""
        _list_lens = self._list_lens
        if k < _list_lens[0]:
            return (0, k)
        if k >= self._len - _list_lens[-1]:
            return (len(_list_lens) - 1, k + _list_lens[-1] - self._len)
        if self._rebuild:
            self._fen_build()
        _fen_tree = self._fen_tree
        idx = -1
        for d in reversed(range(len(_fen_tree).bit_length())):
            right_idx = idx + (1 << d)
            if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]:
                idx = right_idx
                k -= _fen_tree[idx]
        return (idx + 1, k)

    def _delete(self, pos, idx):
        """"""
        _lists = self._lists
        _mins = self._mins
        _list_lens = self._list_lens
        self._len -= 1
        self._fen_update(pos, -1)
        del _lists[pos][idx]
        _list_lens[pos] -= 1
        if _list_lens[pos]:
            _mins[pos] = _lists[pos][0]
        else:
            del _lists[pos]
            del _list_lens[pos]
            del _mins[pos]
            self._rebuild = True

    def _loc_left(self, value):
        """"""
        if not self._len:
            return (0, 0)
        _lists = self._lists
        _mins = self._mins
        (lo, pos) = (-1, len(_lists) - 1)
        while lo + 1 < pos:
            mi = lo + pos >> 1
            if value <= _mins[mi]:
                pos = mi
            else:
                lo = mi
        if pos and value <= _lists[pos - 1][-1]:
            pos -= 1
        _list = _lists[pos]
        (lo, idx) = (-1, len(_list))
        while lo + 1 < idx:
            mi = lo + idx >> 1
            if value <= _list[mi]:
                idx = mi
            else:
                lo = mi
        return (pos, idx)

    def _loc_right(self, value):
        """"""
        if not self._len:
            return (0, 0)
        _lists = self._lists
        _mins = self._mins
        (pos, hi) = (0, len(_lists))
        while pos + 1 < hi:
            mi = pos + hi >> 1
            if value < _mins[mi]:
                hi = mi
            else:
                pos = mi
        _list = _lists[pos]
        (lo, idx) = (-1, len(_list))
        while lo + 1 < idx:
            mi = lo + idx >> 1
            if value < _list[mi]:
                idx = mi
            else:
                lo = mi
        return (pos, idx)

    def add(self, value):
        """"""
        _load = self._load
        _lists = self._lists
        _mins = self._mins
        _list_lens = self._list_lens
        self._len += 1
        if _lists:
            (pos, idx) = self._loc_right(value)
            self._fen_update(pos, 1)
            _list = _lists[pos]
            _list.insert(idx, value)
            _list_lens[pos] += 1
            _mins[pos] = _list[0]
            if _load + _load < len(_list):
                _lists.insert(pos + 1, _list[_load:])
                _list_lens.insert(pos + 1, len(_list) - _load)
                _mins.insert(pos + 1, _list[_load])
                _list_lens[pos] = _load
                del _list[_load:]
                self._rebuild = True
        else:
            _lists.append([value])
            _mins.append(value)
            _list_lens.append(1)
            self._rebuild = True

    def discard(self, value):
        """"""
        _lists = self._lists
        if _lists:
            (pos, idx) = self._loc_right(value)
            if idx and _lists[pos][idx - 1] == value:
                self._delete(pos, idx - 1)

    def remove(self, value):
        """"""
        _len = self._len
        self.discard(value)
        if _len == self._len:
            raise ValueError('{0!r} not in list'.format(value))

    def pop(self, index=-1):
        """"""
        (pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
        value = self._lists[pos][idx]
        self._delete(pos, idx)
        return value

    def bisect_left(self, value):
        """"""
        (pos, idx) = self._loc_left(value)
        return self._fen_query(pos) + idx

    def bisect_right(self, value):
        """"""
        (pos, idx) = self._loc_right(value)
        return self._fen_query(pos) + idx

    def count(self, value):
        """"""
        return self.bisect_right(value) - self.bisect_left(value)

    def __len__(self):
        """"""
        return self._len

    def __getitem__(self, index):
        """"""
        (pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
        return self._lists[pos][idx]

    def __delitem__(self, index):
        """"""
        (pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
        self._delete(pos, idx)

    def __contains__(self, value):
        """"""
        _lists = self._lists
        if _lists:
            (pos, idx) = self._loc_left(value)
            return idx < len(_lists[pos]) and _lists[pos][idx] == value
        return False

    def __iter__(self):
        """"""
        return (value for _list in self._lists for value in _list)

    def __reversed__(self):
        """"""
        return (value for _list in reversed(self._lists) for value in reversed(_list))

    def __repr__(self):
        """"""
        return 'SortedList({0})'.format(list(self))

def solve():
    n = int(input())
    A = list(map(int, input().split()))
    q = int(input())
    queries = [tuple(map(int, input().split())) for _ in range(q)]
    ans = -1
    S = SortedList()
    D = dict()
    for (i, (l, r, x)) in enumerate(queries):
        if x == 0:
            continue
        l -= 1
        if D.get(l, 0) != 0:
            D[l] += x
            if D[l] == 0:
                S.remove(l)
        else:
            D[l] = x
            S.add(l)
        if D.get(r, 0) != 0:
            D[r] -= x
            if D[r] == 0:
                S.remove(r)
        else:
            D[r] = -x
            S.add(r)
        if S and D[S[0]] < 0:
            ans = i
            S = SortedList()
            D.clear()
    P = [0] * (n + 1)
    for i in range(ans + 1):
        (l, r, x) = queries[i]
        P[l - 1] += x
        P[r] -= x
    A[0] += P[0]
    for i in range(1, n):
        P[i] += P[i - 1]
        A[i] += P[i]
    return ' '.join(map(str, A))
T = int(input())
out = [solve() for _ in range(T)]
print('\n'.join(map(str, out)))