World of Darkraft: Battle for Azathoth (Codeforces 1320C)
Tags: Others, sortings

Roma is playing a new expansion for his favorite game World of Darkraft. He made a new character and is going for his first grind.Roma has a choice to buy exactly one of $$$n$$$ different weapons and exactly one of $$$m$$$ different armor sets. Weapon $$$i$$$ has attack modifier $$$a_i$$$ and is worth $$$ca_i$$$ coins, and armor set $$$j$$$ has defense modifier $$$b_j$$$ and is worth $$$cb_j$$$ coins.After choosing his equipment Roma can proceed to defeat some monsters. There are $$$p$$$ monsters he can try to defeat. Monster $$$k$$$ has defense $$$x_k$$$, attack $$$y_k$$$ and possesses $$$z_k$$$ coins. Roma can defeat a monster if his weapon's attack modifier is larger than the monster's defense, and his armor set's defense modifier is larger than the monster's attack. That is, a monster $$$k$$$ can be defeated with a weapon $$$i$$$ and an armor set $$$j$$$ if $$$a_i > x_k$$$ and $$$b_j > y_k$$$. After defeating the monster, Roma takes all the coins from them. During the grind, Roma can defeat as many monsters as he likes. Monsters do not respawn, thus each monster can be defeated at most one.Thanks to Roma's excessive donations, we can assume that he has an infinite amount of in-game currency and can afford any of the weapons and armor sets. Still, he wants to maximize the profit of the grind. The profit is defined as the total coins obtained from all defeated monsters minus the cost of his equipment. Note that Roma must purchase a weapon and an armor set even if he can not cover their cost with obtained coins.Help Roma find the maximum profit of the grind.

Input: The first line contains three integers $$$n$$$, $$$m$$$, and $$$p$$$ ($$$1 \leq n, m, p \leq 2 \cdot 10^5$$$) — the number of available weapons, armor sets and monsters respectively.The following $$$n$$$ lines describe available weapons. The $$$i$$$-th of these lines contains two integers $$$a_i$$$ and $$$ca_i$$$ ($$$1 \leq a_i \leq 10^6$$$, $$$1 \leq ca_i \leq 10^9$$$) — the attack modifier and the cost of the weapon $$$i$$$.The following $$$m$$$ lines describe available armor sets. The $$$j$$$-th of these lines contains two integers $$$b_j$$$ and $$$cb_j$$$ ($$$1 \leq b_j \leq 10^6$$$, $$$1 \leq cb_j \leq 10^9$$$) — the defense modifier and the cost of the armor set $$$j$$$.The following $$$p$$$ lines describe monsters. The $$$k$$$-th of these lines contains three integers $$$x_k, y_k, z_k$$$ ($$$1 \leq x_k, y_k \leq 10^6$$$, $$$1 \leq z_k \leq 10^3$$$) — defense, attack and the number of coins of the monster $$$k$$$.

Output: Print a single integer — the maximum profit of the grind.


Sample Inputs:
2 3 3
2 3
4 7
2 4
3 2
5 11
1 2 4
2 1 6
3 4 6

Sample Outputs:
1

Solution (Python):
import sys
readline = sys.stdin.buffer.readline

class Lazysegtree:

    def __init__(self, A, intv, initialize=True, segf=min):
        self.N = len(A)
        self.N0 = 2 ** (self.N - 1).bit_length()
        self.intv = intv
        max = segf
        self.lazy = [0] * (2 * self.N0)
        if initialize:
            self.data = [intv] * self.N0 + A + [intv] * (self.N0 - self.N)
            for i in range(self.N0 - 1, 0, -1):
                self.data[i] = max(self.data[2 * i], self.data[2 * i + 1])
        else:
            self.data = [intv] * (2 * self.N0)

    def _ascend(self, k):
        k = k >> 1
        c = k.bit_length()
        for j in range(c):
            idx = k >> j
            self.data[idx] = max(self.data[2 * idx], self.data[2 * idx + 1]) + self.lazy[idx]

    def _descend(self, k):
        k = k >> 1
        idx = 1
        c = k.bit_length()
        for j in range(1, c + 1):
            idx = k >> c - j
            ax = self.lazy[idx]
            if not ax:
                continue
            self.lazy[idx] = 0
            self.data[2 * idx] += ax
            self.data[2 * idx + 1] += ax
            self.lazy[2 * idx] += ax
            self.lazy[2 * idx + 1] += ax

    def query(self, l, r):
        L = l + self.N0
        R = r + self.N0
        Li = L // (L & -L)
        Ri = R // (R & -R)
        self._descend(Li)
        self._descend(Ri - 1)
        s = self.intv
        while L < R:
            if R & 1:
                R -= 1
                s = max(s, self.data[R])
            if L & 1:
                s = max(s, self.data[L])
                L += 1
            L >>= 1
            R >>= 1
        return s

    def add(self, l, r, x):
        L = l + self.N0
        R = r + self.N0
        Li = L // (L & -L)
        Ri = R // (R & -R)
        while L < R:
            if R & 1:
                R -= 1
                self.data[R] += x
                self.lazy[R] += x
            if L & 1:
                self.data[L] += x
                self.lazy[L] += x
                L += 1
            L >>= 1
            R >>= 1
        self._ascend(Li)
        self._ascend(Ri - 1)

    def binsearch(self, l, r, check, reverse=False):
        L = l + self.N0
        R = r + self.N0
        Li = L // (L & -L)
        Ri = R // (R & -R)
        self._descend(Li)
        self._descend(Ri - 1)
        (SL, SR) = ([], [])
        while L < R:
            if R & 1:
                R -= 1
                SR.append(R)
            if L & 1:
                SL.append(L)
                L += 1
            L >>= 1
            R >>= 1
        if reverse:
            for idx in SR + SL[::-1]:
                if check(self.data[idx]):
                    break
            else:
                return -1
            while idx < self.N0:
                ax = self.lazy[idx]
                self.lazy[idx] = 0
                self.data[2 * idx] += ax
                self.data[2 * idx + 1] += ax
                self.lazy[2 * idx] += ax
                self.lazy[2 * idx + 1] += ax
                idx = idx << 1
                if check(self.data[idx + 1]):
                    idx += 1
            return idx - self.N0
        else:
            for idx in SL + SR[::-1]:
                if check(self.data[idx]):
                    break
            else:
                return -1
            while idx < self.N0:
                ax = self.lazy[idx]
                self.lazy[idx] = 0
                self.data[2 * idx] += ax
                self.data[2 * idx + 1] += ax
                self.lazy[2 * idx] += ax
                self.lazy[2 * idx + 1] += ax
                idx = idx << 1
                if not check(self.data[idx]):
                    idx += 1
            return idx - self.N0
(N, M, P) = map(int, readline().split())
xcx = [tuple(map(int, readline().split())) for _ in range(N)]
ycy = [tuple(map(int, readline().split())) for _ in range(M)]
enemy = [tuple(map(int, readline().split())) for _ in range(P)]
JM = 10 ** 6 + 4
table = [0] * JM
bestarmor = [2147483648] * JM
bestweapon = [2147483648] * JM
event = [[] for _ in range(JM)]
for (y, cy) in ycy:
    bestarmor[y] = min(bestarmor[y], cy)
for (x, cx) in xcx:
    bestweapon[x] = min(bestweapon[x], cx)
for i in range(JM):
    if bestarmor[i] != 2147483648:
        table[i] -= bestarmor[i]
        table[i + 1] += bestarmor[i]
    table[i] += table[i - 1]
table = [t if t else -2147483648 for t in table]
for (x, y, z) in enemy:
    event[x + 1].append((y + 1, z))
T = Lazysegtree(table, -2147483648, initialize=True, segf=max)
cnt = 0
N0 = T.N0
ans = -2147483648
for i in range(JM):
    for (y, z) in event[i]:
        T.add(y, N0, z)
    if bestweapon[i] == 2147483648:
        continue
    else:
        ans = max(ans, T.data[1] - bestweapon[i])
print(ans)

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

def update(l, r, s):
    (q, ll, rr, i) = ([1], [0], [l1 - 1], 0)
    while len(q) ^ i:
        j = q[i]
        (l0, r0) = (ll[i], rr[i])
        if l <= l0 and r0 <= r:
            lazy[j] += s
            i += 1
            continue
        m0 = l0 + r0 >> 1
        if j < l1 and lazy[j]:
            lazy[j << 1] += lazy[j]
            lazy[j << 1 ^ 1] += lazy[j]
            lazy[j] = 0
        if l <= m0 and l0 <= r:
            q.append(j << 1)
            ll.append(l0)
            rr.append(m0)
        if l <= r0 and m0 + 1 <= r:
            q.append(j << 1 ^ 1)
            ll.append(m0 + 1)
            rr.append(r0)
        i += 1
    for i in reversed(q):
        if i < l1:
            (j, k) = (i << 1, i << 1 ^ 1)
            tree[i] = max(tree[j] + lazy[j], tree[k] + lazy[k])
    return
(n, m, p) = map(int, input().split())
a = [tuple(map(int, input().split())) for _ in range(n)]
b = [tuple(map(int, input().split())) for _ in range(m)]
xyz = [tuple(map(int, input().split())) for _ in range(p)]
l = pow(10, 6) + 5
s = [0] * l
for (b0, _) in b:
    s[b0] = 1
for i in range(1, l):
    s[i] += s[i - 1]
c = s[-1]
l1 = pow(2, (c + 5).bit_length())
l2 = 2 * l1
inf = 2 * pow(10, 9) + 1
(tree, lazy) = ([-inf] * l2, [0] * l2)
ma1 = -inf
for (b0, cb) in b:
    ma1 = max(ma1, -cb)
    tree[s[b0] + l1] = max(tree[s[b0] + l1], -cb)
for i in range(l1 - 1, 0, -1):
    tree[i] = max(tree[2 * i], tree[2 * i + 1])
da = [-inf] * l
dx = [[] for _ in range(l)]
ma2 = -inf
for (a0, ca) in a:
    ma2 = max(ma2, -ca)
    da[a0] = max(da[a0], -ca)
for (x, y, z) in xyz:
    dx[x].append((y, z))
ans = ma1 + ma2
for i in range(1, l):
    if da[i] ^ -inf:
        ans = max(ans, tree[1] + lazy[1] + da[i])
    for (y, z) in dx[i]:
        update(s[y] + 1, c + 1, z)
print(ans)

Solution (Python):
class LazySegmentTree:

    def __init__(self, data, func=max):
        """"""
        self._func = func
        self._len = len(data)
        self._size = _size = 1 << (self._len - 1).bit_length()
        self._lazy = [0] * (2 * _size)
        self.data = [-int(2000000000.0 - 5)] * (2 * _size)
        self.data[_size:_size + self._len] = data
        for i in reversed(range(_size)):
            self.data[i] = self._func(self.data[i + i], self.data[i + i + 1])

    def __len__(self):
        return self._len

    def _push(self, idx):
        """"""
        (q, self._lazy[idx]) = (self._lazy[idx], 0)
        self._lazy[2 * idx] += q
        self._lazy[2 * idx + 1] += q
        self.data[2 * idx] += q
        self.data[2 * idx + 1] += q

    def _update(self, idx):
        """"""
        for i in reversed(range(1, idx.bit_length())):
            self._push(idx >> i)

    def _build(self, idx):
        """"""
        idx >>= 1
        while idx:
            self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1]) + self._lazy[idx]
            idx >>= 1

    def add(self, start, stop, value):
        """"""
        stop += 1
        start = start_copy = start + self._size
        stop = stop_copy = stop + self._size
        while start < stop:
            if start & 1:
                self._lazy[start] += value
                self.data[start] += value
                start += 1
            if stop & 1:
                stop -= 1
                self._lazy[stop] += value
                self.data[stop] += value
            start >>= 1
            stop >>= 1
        self._build(start_copy)
        self._build(stop_copy - 1)

    def query(self, start, stop):
        """"""
        stop += 1
        start += self._size
        stop += self._size
        self._update(start)
        self._update(stop - 1)
        res = -int(2000000000.0)
        while start < stop:
            if start & 1:
                res = self._func(res, self.data[start])
                start += 1
            if stop & 1:
                stop -= 1
                res = self._func(res, self.data[stop])
            start >>= 1
            stop >>= 1
        return res

    def __repr__(self):
        return 'LazySegmentTree({0})'.format(self.data)

def main():
    (n, m, p) = readIntArr()
    aca = []
    for _ in range(n):
        (a, ca) = readIntArr()
        aca.append((a, ca))
    bcb = []
    for _ in range(m):
        (b, cb) = readIntArr()
        bcb.append((b, cb))
    yxz = []
    for _ in range(p):
        (x, y, z) = readIntArr()
        yxz.append((y, x, z))
    aca.sort(key=lambda x: x[0])
    segArr = [-ca for (a, ca) in aca]
    lst = LazySegmentTree(segArr)
    bcb.sort(key=lambda x: x[0])
    yxz.sort(key=lambda x: x[0])
    ans = -2000000000.0 - 5
    i = 0
    for (b, cb) in bcb:
        while i < p and yxz[i][0] < b:
            (y, x, z) = yxz[i]
            lo = -1
            hi = n - 1
            while lo < hi:
                mid = (lo + hi + 1) // 2
                if aca[mid][0] <= x:
                    lo = mid
                else:
                    hi = mid - 1
            j = lo + 1
            if j < n:
                lst.add(j, n - 1, z)
            i += 1
        ans = max(ans, -cb + lst.query(0, n - 1))
    print(ans)
    return
import sys
input = sys.stdin.buffer.readline

def oneLineArrayPrint(arr):
    print(' '.join([str(x) for x in arr]))

def multiLineArrayPrint(arr):
    print('\n'.join([str(x) for x in arr]))

def multiLineArrayOfArraysPrint(arr):
    print('\n'.join([' '.join([str(x) for x in y]) for y in arr]))

def readIntArr():
    return [int(x) for x in input().split()]

def makeArr(defaultValFactory, dimensionArr):
    dv = defaultValFactory
    da = dimensionArr
    if len(da) == 1:
        return [dv() for _ in range(da[0])]
    else:
        return [makeArr(dv, da[1:]) for _ in range(da[0])]

def queryInteractive(a, b, c):
    print('? {} {} {}'.format(a, b, c))
    sys.stdout.flush()
    return int(input())

def answerInteractive(ansArr):
    print('! {}'.format(' '.join([str(x) for x in ansArr])))
    sys.stdout.flush()
inf = float('inf')
from math import gcd, floor, ceil
import math
for _abc in range(1):
    main()