Problem:


Score: 600 points

Problem Statement

There is a grass field that stretches infinitely.

In this field, there is a negligibly small cow. Let (x, y) denote the point that is x\ \mathrm{cm} south and y\ \mathrm{cm} east of the point where the cow stands now. The cow itself is standing at (0, 0).

There are also N north-south lines and M east-west lines drawn on the field. The i-th north-south line is the segment connecting the points (A_i, C_i) and (B_i, C_i), and the j-th east-west line is the segment connecting the points (D_j, E_j) and (D_j, F_j).

What is the area of the region the cow can reach when it can move around as long as it does not cross the segments (including the endpoints)? If this area is infinite, print INF instead.

Constraints

All values in input are integers between -10^9 and 10^9  (inclusive).

1 \leq N, M \leq 1000

A_i < B_i\ (1 \leq i \leq N)

E_j < F_j\ (1 \leq j \leq M)

The point (0, 0) does not lie on any of the given segments.

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1 C_1
:
A_N B_N C_N
D_1 E_1 F_1
:
D_M E_M F_M

Output

If the area of the region the cow can reach is infinite, print INF; otherwise, print an integer representing the area in \mathrm{cm^2}.

(Under the constraints, it can be proved that the area of the region is always an integer if it is not infinite.)

Sample Input 1

5 6
1 2 0
0 1 1
0 2 2
-3 4 -1
-2 6 3
1 0 1
0 1 2
2 0 2
-1 -4 5
3 -2 4
1 2 4

Sample Output 1

13

The area of the region the cow can reach is 13\ \mathrm{cm^2}.

Sample Input 2

6 1
-3 -1 -2
-3 -1 1
-2 -1 2
1 4 -2
1 4 -1
1 4 1
3 1 4

Sample Output 2

INF

The area of the region the cow can reach is infinite.



Sample input:
5 6
1 2 0
0 1 1
0 2 2
-3 4 -1
-2 6 3
1 0 1
0 1 2
2 0 2
-1 -4 5
3 -2 4
1 2 4


Sample output:
13

Submission status: Memory Limit Exceeded

Solution code:
#!/usr/bin/env python3

from collections import defaultdict
from heapq import heappush, heappop
import sys
import numpy as np
import numba

sys.setrecursionlimit(10**6)
input = sys.stdin.buffer.readline
# INF = sys.maxsize
INF = 10 ** 10
# INF = float("inf")


def dp(*x):  # debugprint
    print(*x)


try:
    profile
except:
    def profile(f): return f


@numba.jit
def bisect_left(a, x):
    """Return the index where to insert item x in list a, assuming a is sorted.
    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.
    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """
    lo = 0
    hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # Use __lt__ to match the logic in list.sort() and in heapq
        if x < a[mid]:
            hi = mid
        else:
            lo = mid+1
    return lo


def main(N, M, data):
    # vlines = defaultdict(lambda: [(0, 0)])
    vlines = {}
    # hlines = defaultdict(lambda: [(0, 0)])
    hlines = {}
    # vticks = {0}
    vticks = {0}
    # hticks = {0}
    hticks = {0}

    ABC = data[:3 * N]
    DEF = data[3 * N:]
    A, B, C = [ABC[i::3] for i in range(3)]
    D, E, F = [DEF[i::3] for i in range(3)]

    xticks = np.unique(np.concatenate((E, F, C, np.array([-INF, 0, INF]))))
    yticks = np.unique(np.concatenate((A, B, D, np.array([-INF, 0, INF]))))
    width = xticks[1:] - xticks[:-1]
    height = yticks[1:] - yticks[:-1]

    # compress
    A = np.searchsorted(yticks, A)
    B = np.searchsorted(yticks, B)
    C = np.searchsorted(xticks, C)
    D = np.searchsorted(yticks, D)
    E = np.searchsorted(xticks, E)
    F = np.searchsorted(xticks, F)

    GRAPH_WIDTH = len(xticks)
    GRAPH_HEIGHT = len(yticks)
    NUM_VERTEXES = GRAPH_HEIGHT * GRAPH_WIDTH

    ng_egdes = np.zeros((NUM_VERTEXES, 4), dtype=np.bool_)
    direction = (-1, +1, -GRAPH_WIDTH, +GRAPH_WIDTH)

    # vertical lines A,C-B,C
    for i in range(N):
        x = C[i]
        for y in range(A[i], B[i]):
            pos = y * GRAPH_WIDTH + x
            ng_egdes[pos, 0] = 1  # left
            ng_egdes[pos - 1, 1] = 1  # right

    # horizontal lines D,E-D,F
    hbound = np.array([0, 0, 1, 1])
    for i in range(M):
        y = D[i]
        for x in range(E[i], F[i]):
            pos = y * GRAPH_WIDTH + x
            ng_egdes[pos, 2] = 1
            ng_egdes[pos - GRAPH_WIDTH, 3] = 1

    A = B = C = D = E = F = 0

    total_area = 0
    #visited = np.zeros(N)
    visited = set()
    x = np.searchsorted(xticks, 0)
    y = np.searchsorted(yticks, 0)
    start = y * GRAPH_WIDTH + x
    to_visit = [start]

    while to_visit:
        pos = to_visit.pop()
        y, x = divmod(pos, GRAPH_WIDTH)
        if pos in visited:
            continue
        if y == 0 or y == GRAPH_HEIGHT - 1 or x == 0 or x == GRAPH_WIDTH - 1:
            print("INF")
            break

        total_area += width[x] * height[y]
        visited.add(pos)
        # plan to visit neighbors
        for i in range(4):
            if not ng_egdes[pos, i]:
                to_visit.append(pos + direction[i])
    else:
        print(total_area)


if sys.argv[-1] == 'ONLINE_JUDGE' or sys.argv[-1] == '-c':
    print("compiling")
    from numba.pycc import CC
    cc = CC('my_module')
    cc.export(
        'main',
        "void(i8, i8, i8[:])"
    )(main)
    # b1: bool, i4: int32, i8: int64, double: f8, [:], [:, :]
    cc.compile()
    exit()
else:
    if sys.argv[-1] != '-p':
        # -p: pure python mode
        # if not -p, import compiled module
        from my_module import main  # pylint: disable=all

    # read parameter
    import numba
    N, M = map(int, input().split())
    data = np.int64(sys.stdin.read().split())
    main(N, M, data)

Submission status: Memory Limit Exceeded

Solution code:
#!/usr/bin/env python3

from collections import defaultdict
from heapq import heappush, heappop
import sys
import numpy as np
import numba

sys.setrecursionlimit(10**6)
input = sys.stdin.buffer.readline
# INF = sys.maxsize
INF = 10 ** 10
# INF = float("inf")


def dp(*x):  # debugprint
    print(*x)


try:
    profile
except:
    def profile(f): return f


@numba.jit
def bisect_left(a, x):
    """Return the index where to insert item x in list a, assuming a is sorted.
    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.
    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """
    lo = 0
    hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # Use __lt__ to match the logic in list.sort() and in heapq
        if x < a[mid]:
            hi = mid
        else:
            lo = mid+1
    return lo


def main(N, M, data):
    # vlines = defaultdict(lambda: [(0, 0)])
    vlines = {}
    # hlines = defaultdict(lambda: [(0, 0)])
    hlines = {}
    # vticks = {0}
    vticks = {0}
    # hticks = {0}
    hticks = {0}

    ABC = data[:3 * N]
    DEF = data[3 * N:]
    A, B, C = [ABC[i::3] for i in range(3)]
    D, E, F = [DEF[i::3] for i in range(3)]

    xticks = np.unique(np.concatenate((E, F, C, np.array([-INF, 0, INF]))))
    yticks = np.unique(np.concatenate((A, B, D, np.array([-INF, 0, INF]))))
    width = xticks[1:] - xticks[:-1]
    height = yticks[1:] - yticks[:-1]

    # compress
    A = np.searchsorted(yticks, A)
    B = np.searchsorted(yticks, B)
    C = np.searchsorted(xticks, C)
    D = np.searchsorted(yticks, D)
    E = np.searchsorted(xticks, E)
    F = np.searchsorted(xticks, F)

    GRAPH_WIDTH = len(xticks)
    GRAPH_HEIGHT = len(yticks)
    NUM_VERTEXES = GRAPH_HEIGHT * GRAPH_WIDTH

    ng_egdes = np.zeros((NUM_VERTEXES, 4), dtype=np.int16)
    direction = (-1, +1, -GRAPH_WIDTH, +GRAPH_WIDTH)

    # vertical lines A,C-B,C
    for i in range(N):
        x = C[i]
        for y in range(A[i], B[i]):
            pos = y * GRAPH_WIDTH + x
            ng_egdes[pos, 0] = 1  # left
            ng_egdes[pos - 1, 1] = 1  # right

    # horizontal lines D,E-D,F
    hbound = np.array([0, 0, 1, 1])
    for i in range(M):
        y = D[i]
        for x in range(E[i], F[i]):
            pos = y * GRAPH_WIDTH + x
            ng_egdes[pos, 2] = 1
            ng_egdes[pos - GRAPH_WIDTH, 3] = 1

    A = B = C = D = E = F = 0

    total_area = 0
    #visited = np.zeros(N)
    visited = set()
    x = np.searchsorted(xticks, 0)
    y = np.searchsorted(yticks, 0)
    start = y * GRAPH_WIDTH + x
    to_visit = [start]

    while to_visit:
        pos = to_visit.pop()
        y, x = divmod(pos, GRAPH_WIDTH)
        if pos in visited:
            continue
        if y == 0 or y == GRAPH_HEIGHT - 1 or x == 0 or x == GRAPH_WIDTH - 1:
            print("INF")
            break

        total_area += width[x] * height[y]
        visited.add(pos)
        # plan to visit neighbors
        for i in range(4):
            if not ng_egdes[pos, i]:
                to_visit.append(pos + direction[i])
    else:
        print(total_area)


if sys.argv[-1] == 'ONLINE_JUDGE' or sys.argv[-1] == '-c':
    print("compiling")
    from numba.pycc import CC
    cc = CC('my_module')
    cc.export(
        'main',
        "void(i8, i8, i8[:])"
    )(main)
    # b1: bool, i4: int32, i8: int64, double: f8, [:], [:, :]
    cc.compile()
    exit()
else:
    if sys.argv[-1] != '-p':
        # -p: pure python mode
        # if not -p, import compiled module
        from my_module import main  # pylint: disable=all

    # read parameter
    import numba
    N, M = map(int, input().split())
    data = np.int64(sys.stdin.read().split())
    main(N, M, data)

Submission status: Memory Limit Exceeded

Solution code:
#!/usr/bin/env python3

from collections import defaultdict
from heapq import heappush, heappop
import sys
import numpy as np
import numba

sys.setrecursionlimit(10**6)
input = sys.stdin.buffer.readline
# INF = sys.maxsize
INF = 10 ** 10
# INF = float("inf")


def dp(*x):  # debugprint
    print(*x)


try:
    profile
except:
    def profile(f): return f


@numba.jit
def bisect_left(a, x):
    """Return the index where to insert item x in list a, assuming a is sorted.
    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.
    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """
    lo = 0
    hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # Use __lt__ to match the logic in list.sort() and in heapq
        if x < a[mid]:
            hi = mid
        else:
            lo = mid+1
    return lo


def main(N, M, data):
    # vlines = defaultdict(lambda: [(0, 0)])
    vlines = {}
    # hlines = defaultdict(lambda: [(0, 0)])
    hlines = {}
    # vticks = {0}
    vticks = {0}
    # hticks = {0}
    hticks = {0}

    ABC = data[:3 * N]
    DEF = data[3 * N:]
    A, B, C = [ABC[i::3] for i in range(3)]
    D, E, F = [DEF[i::3] for i in range(3)]

    xticks = np.unique(np.concatenate((E, F, C, np.array([-INF, 0, INF]))))
    yticks = np.unique(np.concatenate((A, B, D, np.array([-INF, 0, INF]))))
    width = xticks[1:] - xticks[:-1]
    height = yticks[1:] - yticks[:-1]

    # compress
    A = np.searchsorted(yticks, A)
    B = np.searchsorted(yticks, B)
    C = np.searchsorted(xticks, C)
    D = np.searchsorted(yticks, D)
    E = np.searchsorted(xticks, E)
    F = np.searchsorted(xticks, F)

    GRAPH_WIDTH = len(xticks)
    GRAPH_HEIGHT = len(yticks)
    NUM_VERTEXES = GRAPH_HEIGHT * GRAPH_WIDTH

    ng_egdes = np.zeros((NUM_VERTEXES, 4), dtype=np.int16)
    direction = (-1, +1, -GRAPH_WIDTH, +GRAPH_WIDTH)

    # vertical lines A,C-B,C
    for i in range(N):
        x = C[i]
        for y in range(A[i], B[i]):
            pos = y * GRAPH_WIDTH + x
            ng_egdes[pos, 0] = 1  # left
            ng_egdes[pos - 1, 1] = 1  # right

    # horizontal lines D,E-D,F
    hbound = np.array([0, 0, 1, 1])
    for i in range(M):
        y = D[i]
        for x in range(E[i], F[i]):
            pos = y * GRAPH_WIDTH + x
            ng_egdes[pos, 2] = 1
            ng_egdes[pos - GRAPH_WIDTH, 3] = 1

    total_area = 0
    #visited = np.zeros(N)
    visited = set()
    x = np.searchsorted(xticks, 0)
    y = np.searchsorted(yticks, 0)
    start = y * GRAPH_WIDTH + x
    to_visit = [start]

    while to_visit:
        pos = to_visit.pop()
        y, x = divmod(pos, GRAPH_WIDTH)
        if pos in visited:
            continue
        if y == 0 or y == GRAPH_HEIGHT - 1 or x == 0 or x == GRAPH_WIDTH - 1:
            print("INF")
            break

        total_area += width[x] * height[y]
        visited.add(pos)
        # plan to visit neighbors
        for i in range(4):
            if not ng_egdes[pos, i]:
                to_visit.append(pos + direction[i])
    else:
        print(total_area)


if sys.argv[-1] == 'ONLINE_JUDGE' or sys.argv[-1] == '-c':
    print("compiling")
    from numba.pycc import CC
    cc = CC('my_module')
    cc.export(
        'main',
        "void(i8, i8, i8[:])"
    )(main)
    # b1: bool, i4: int32, i8: int64, double: f8, [:], [:, :]
    cc.compile()
    exit()
else:
    if sys.argv[-1] != '-p':
        # -p: pure python mode
        # if not -p, import compiled module
        from my_module import main  # pylint: disable=all

    # read parameter
    import numba
    N, M = map(int, input().split())
    data = np.int64(sys.stdin.read().split())
    main(N, M, data)

Submission status: Memory Limit Exceeded

Solution code:
import sys

# from itertools import chain, accumulate

n, m, *abcdef = map(int, sys.stdin.buffer.read().split())

ver_lines = []
hor_lines = []
x_list = set()
y_list = set()
n3 = n * 3
for a, b, c in zip(abcdef[0:n3:3], abcdef[1:n3:3], abcdef[2:n3:3]):
    y_list.add(a)
    y_list.add(b)
    x_list.add(c)
    ver_lines.append((a, b, c))

for d, e, f in zip(abcdef[n3 + 0::3], abcdef[n3 + 1::3], abcdef[n3 + 2::3]):
    y_list.add(d)
    x_list.add(e)
    x_list.add(f)
    hor_lines.append((d, e, f))
x_list.add(0)
y_list.add(0)

x_list = sorted(x_list)
y_list = sorted(y_list)
x_dict = {x: i for i, x in enumerate(x_list, start=1)}
y_dict = {y: i for i, y in enumerate(y_list, start=1)}
row_real = len(x_list)
col_real = len(y_list)
row = row_real + 2
col = col_real + 2

banned_up = [0] * (row * col)
banned_down = [0] * (row * col)
banned_left = [0] * (row * col)
banned_right = [0] * (row * col)
banned_up_ij = [[0] * row for _ in range(col)]
banned_down_ij = [[0] * row for _ in range(col)]
banned_left_ij = [[0] * col for _ in range(row)]
banned_right_ij = [[0] * col for _ in range(row)]
for a, b, c in ver_lines:
    if a > b:
        a, b = b, a
    ai = y_dict[a] * row
    bi = y_dict[b] * row
    j = x_dict[c]
    banned_left[ai + j] += 1
    banned_left[bi + j] -= 1
    banned_right[ai + j - 1] += 1
    banned_right[bi + j - 1] -= 1
for d, e, f in hor_lines:
    if e > f:
        e, f = f, e
    ri = y_dict[d] * row
    ej = x_dict[e]
    fj = x_dict[f]
    banned_up[ri + ej] += 1
    banned_up[ri + fj] -= 1
    banned_down[ri - row + ej] += 1
    banned_down[ri - row + fj] -= 1

for i in range(col):
    ri = row * i
    for j in range(1, row):
        banned_up[ri + j] += banned_up[ri + j - 1]
        banned_down[ri + j] += banned_down[ri + j - 1]
for j in range(row):
    for i in range(1, col):
        ri0 = (i - 1) * row
        ri1 = i * row
        banned_left[ri1 + j] += banned_left[ri0 + j]
        banned_right[ri1 + j] += banned_right[ri0 + j]

# banned_up = list(chain.from_iterable(map(accumulate, banned_up_ij)))
# banned_down = list(chain.from_iterable(map(accumulate, banned_down_ij)))
# banned_left = list(chain.from_iterable(zip(*map(accumulate, banned_left_ij))))
# banned_right = list(chain.from_iterable(zip(*map(accumulate, banned_right_ij))))

# for i in range(col):
#     print(walls[i * row:(i + 1) * row])

s = row * y_dict[0] + x_dict[0]
enable = [-1] * row + ([-1] + [0] * (row - 2) + [-1]) * (col - 2) + [-1] * row

# for i in range(col):
#     print(enable[i * row:(i + 1) * row])

q = [s]
moves = [(-row, banned_up), (-1, banned_left), (1, banned_right), (row, banned_down)]
while q:
    c = q.pop()
    if enable[c] == 1:
        continue
    elif enable[c] == -1:
        print('INF')
        exit()
    enable[c] = 1
    for dc, banned in moves:
        if banned[c]:
            continue
        nc = c + dc
        if enable[nc] == 1:
            continue
        q.append(nc)
# for i in range(col):
#     print(enable[i * row:(i + 1) * row])


ans = 0
for i in range(col):
    ri = i * row
    for j in range(row):
        if enable[ri + j] != 1:
            continue
        t = y_list[i - 1]
        b = y_list[i]
        l = x_list[j - 1]
        r = x_list[j]
        ans += (b - t) * (r - l)
print(ans)

Submission status: Accepted

Solution code:
# ABC168F .(Single Dot)
from collections import deque

g=lambda:map(int,input().split())

N,M=g()

sortx=[]
sorty=[]

y_line=[0]*N
x_line=[0]*M

for i in range(N):
    a,b,c=g()
    sortx.append(a)
    sortx.append(b)
    sorty.append(c)
    y_line[i]=(a,b,c)
    
for i in range(M):
    d,e,f=g()
    sortx.append(d)
    sorty.append(e)
    sorty.append(f)
    x_line[i]=(d,e,f)
    
from bisect import bisect_left as bl
    
sortx=sorted(list(set(sortx)))
sorty=sorted(list(set(sorty)))

for i in range(N):
    a,b,c=y_line[i]
    a=bl(sortx,a)
    b=bl(sortx,b)
    c=bl(sorty,c)
    y_line[i]=(a,b,c)
    
for i in range(M):
    d,e,f=x_line[i]
    d=bl(sortx,d)
    e=bl(sorty,e)
    f=bl(sorty,f)
    x_line[i]=(d,e,f)
    
W=len(sortx)*2-1
H=len(sorty)*2-1
    
G=[1]*W*H

def make_graph(i,j,s=0):
    G[i+j*W]=s
    
def isOK(x,y):
    if 0<=x+y*W<W*H:
        return G[x+y*W]==1
    else:
        return False
    
def isSoto(x,y):
    return (not 0<=x+y*W<W*H)

def get_score(i,j):
    if i<=0 or j<=0  or i>=W or j>=H:
        return float('inf')
    elif i%2 and j%2:
        dx=sortx[(i+1)//2]-sortx[(i-1)//2]
        dy=sorty[(j+1)//2]-sorty[(j-1)//2]
        return dx*dy
    else:
        return 0

dic=[(-1,0),(1,0),(0,1),(0,-1)]
def search(i,j):
    res=[]
    for dx,dy in dic:
        if isOK(i+dx,j+dy) and (isOK(i+2*dx,j+2*dy) or isSoto(i+2*dx,j+2*dy)):
            res.append((i+2*dx,j+2*dy))
    return res

for a,b,c in y_line:
    for i in range(2*a,2*b+1):
        make_graph(i,2*c)
        
for d,e,f in x_line:
    for j in range(2*e,2*f+1):
        make_graph(2*d,j)
        
x0,y0=2*bl(sortx,0)-1,2*bl(sorty,0)-1

stack=deque()

for dx,dy in [(-1,-1),(-1,1),(1,1),(1,-1)]:
    if isOK(x0+dx,y0) or isOK(x0,y0+dy):
        stack.append((x0+dx,y0+dy))

stack.append((x0,y0))
res=0
make_graph(x0,y0,1)
while stack:
    x,y=stack.popleft()
    if isSoto(x,y):
        res+=get_score(x,y)
        break
    if not isOK(x,y):
        continue
    res+=get_score(x,y)
    for nx,ny in search(x,y):
        stack.append((nx,ny))
    make_graph(x,y)

print(res if res<float('inf') else 'INF')

Submission status: Accepted

Solution code:
import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
def resolve():
    m, n = map(int, input().split())
    horizontal, vertical = [], []
    X, Y = {-INF, 0, INF}, {-INF, 0, INF}

    for _ in range(m):
        x0, x1, y = map(int, input().split())
        horizontal.append((x0, x1, y))
        X.add(x0)
        X.add(x1)
        Y.add(y)
    for _ in range(n):
        x, y0, y1 = map(int, input().split())
        vertical.append((x, y0, y1))
        X.add(x)
        Y.add(y0)
        Y.add(y1)
    X = sorted(X)
    Y = sorted(Y)

    # compress
    m, n = len(X), len(Y)
    cX = {v : i for i, v in enumerate(X)}
    cY = {v : i for i, v in enumerate(Y)}

    # make grid
    grid_hor = [[True] * n for _ in range(m)]
    grid_ver = [[True] * n for _ in range(m)]
    for x0, x1, y in horizontal:
        y = cY[y]
        for x in range(cX[x0], cX[x1]):
            grid_hor[x][y] = False
    for x, y0, y1 in vertical:
        x = cX[x]
        for y in range(cY[y0], cY[y1]):
            grid_ver[x][y] = False

    # bfs
    ans = 0
    queue = [(cX[0], cY[0])]
    used = [[False] * n for _ in range(m)]
    used[cX[0]][cY[0]] = True
    while queue:
        nQ = []
        for x, y in queue:
            if x == 0 or y == 0 or x == m - 1 or y == n - 1:
                print("INF")
                return
            ans += (X[x + 1] - X[x]) * (Y[y + 1] - Y[y])
            # up
            if y + 1 < n and grid_hor[x][y + 1] and not used[x][y + 1]:
                used[x][y + 1] = True
                nQ.append((x, y + 1))
            # down
            if y - 1 >= 0 and grid_hor[x][y] and not used[x][y - 1]:
                used[x][y - 1] = True
                nQ.append((x, y - 1))
            # right
            if x + 1 < m and grid_ver[x + 1][y] and not used[x + 1][y]:
                used[x + 1][y] = True
                nQ.append((x + 1, y))
            # left
            if x - 1 >= 0 and grid_ver[x][y] and not used[x - 1][y]:
                used[x - 1][y] = True
                nQ.append((x - 1, y))
        queue = nQ

    print(ans)
resolve()

Submission status: Accepted

Solution code:
import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
from collections import deque
def resolve():
    m, n = map(int, input().split())
    horizontal, vertical = [], []
    X, Y = {-INF, 0, INF}, {-INF, 0, INF}

    for _ in range(m):
        x0, x1, y = map(int, input().split())
        horizontal.append((x0, x1, y))
        X.add(x0)
        X.add(x1)
        Y.add(y)
    for _ in range(n):
        x, y0, y1 = map(int, input().split())
        vertical.append((x, y0, y1))
        X.add(x)
        Y.add(y0)
        Y.add(y1)
    X = sorted(X)
    Y = sorted(Y)

    # compress
    m, n = len(X), len(Y)
    cX = {v : i for i, v in enumerate(X)}
    cY = {v : i for i, v in enumerate(Y)}

    # make grid
    grid_hor = [[True] * n for _ in range(m)]
    grid_ver = [[True] * n for _ in range(m)]
    for x0, x1, y in horizontal:
        y = cY[y]
        for x in range(cX[x0], cX[x1]):
            grid_hor[x][y] = False
    for x, y0, y1 in vertical:
        x = cX[x]
        for y in range(cY[y0], cY[y1]):
            grid_ver[x][y] = False

    # bfs
    ans = 0
    queue = deque([(cX[0], cY[0])])
    used = [[False] * n for _ in range(m)]
    used[cX[0]][cY[0]] = True
    while queue:
        x, y = queue.popleft()
        if x == 0 or y == 0 or x == m - 1 or y == n - 1:
            print("INF")
            return
        ans += (X[x + 1] - X[x]) * (Y[y + 1] - Y[y])
        # up
        if y + 1 < n and grid_hor[x][y + 1] and not used[x][y + 1]:
            used[x][y + 1] = True
            queue.append((x, y + 1))
        # down
        if y - 1 >= 0 and grid_hor[x][y] and not used[x][y - 1]:
            used[x][y - 1] = True
            queue.append((x, y - 1))
        # right
        if x + 1 < m and grid_ver[x + 1][y] and not used[x + 1][y]:
            used[x + 1][y] = True
            queue.append((x + 1, y))
        # left
        if x - 1 >= 0 and grid_ver[x][y] and not used[x - 1][y]:
            used[x - 1][y] = True
            queue.append((x - 1, y))

    print(ans)
resolve()

Submission status: Accepted

Solution code:
N, M = map(int, input().split())
A, B, C = [], [], []
for _ in range(N):
  a, b, c = map(int, input().split())
  A.append(a)
  B.append(b)
  C.append(c)
D, E, F = [], [], []
for _ in range(M):
  d, e, f = map(int, input().split())
  D.append(d)
  E.append(e)
  F.append(f)

orig_X = sorted(set([0] + D))
orig_Y = sorted(set([0] + C))
                
X = {x: i for i, x in enumerate(orig_X)}
Y = {y: i for i, y in enumerate(orig_Y)}
max_X = len(X) - 1
max_Y = len(Y) - 1
#print(X, Y)

movable = [(-1, 0), (1, 0), (0, -1), (0, 1)]
blocked = {}
# (x, y) -> stands at (x+0.5, y+0.5)
for a, b, c in zip(A, B, C):
  y = Y[c]
  Xa = -1
  Xb = -1
  for i, x in enumerate(orig_X):
    if Xa < 0 and x >= a:
      Xa = i
    if x > b:
      break
    Xb = i
  #for x in range(X[a], X[b]):
  for x in range(Xa, Xb):
    if y < max_Y:
      if (x, y) not in blocked:
        blocked[(x, y)] = set()
      blocked[(x, y)].add((0, -1))
    if y > 0:
      if (x, y-1) not in blocked:
        blocked[(x, y-1)] = set()
      blocked[(x, y-1)].add((0, +1))

for d, e, f in zip(D, E, F):
  x = X[d]
  Ye = -1
  Yf = -1
  for i, y in enumerate(orig_Y):
    if Ye < 0 and y >= e:
      Ye = i
    if y > f:
      break
    Yf = i
  # for y in range(Y[e], Y[f]):
  for y in range(Ye, Yf):
    if (x, y) not in blocked:
      blocked[(x, y)] = set()
    blocked[(x, y)].add((-1, 0))
    if x > 0:
      if (x-1, y) not in blocked:
        blocked[(x-1, y)] = set()
      blocked[(x-1, y)].add((+1, 0))

#print(sorted(blocked))

visited = [0] * max_X * max_Y
def get_visited(x, y):
  return visited[x * max_Y + y]
def set_visited(x, y):
  #print(x,y)
  visited[x * max_Y + y] = True

to_visit = [(X[0], Y[0])]
while to_visit:
  #print(to_visit)
  x, y = to_visit.pop()
  if x < 0 or x >= max_X or y < 0 or y >= max_Y:
    print('INF')
    exit()
  if get_visited(x, y):
    continue
  set_visited(x, y)
  for d in movable:
    if (x, y) in blocked and d in blocked[(x, y)]:
      continue
    to_visit.append((x + d[0], y + d[1]))

ans = 0
for x in range(0, max_X):
  for y in range(0, max_Y):
    if get_visited(x, y):
      ans += (orig_X[x+1] - orig_X[x]) * (
        orig_Y[y+1] - orig_Y[y])
print(ans)

Submission status: Accepted

Solution code:
def numba_compile(numba_config):
    import os, sys
    if sys.argv[-1] == "ONLINE_JUDGE":
        from numba import njit
        from numba.pycc import CC
        cc = CC("my_module")
        for func, signature in numba_config:
            globals()[func.__name__] = njit(signature)(func)
            cc.export(func.__name__, signature)(func)
        cc.compile()
        exit()
    elif os.name == "posix":
        exec(f"from my_module import {','.join(func.__name__ for func, _ in numba_config)}")
        for func, _ in numba_config:
            globals()[func.__name__] = vars()[func.__name__]
    else:
        from numba import njit
        for func, signature in numba_config:
            globals()[func.__name__] = njit(signature, cache=True)(func)
        print("compiled!", file=sys.stderr)

import sys
import numpy as np

def solve(N, M, ABCDEF):
    L, R, U, D = 0, 1, 2, 3
    Dy = [0, 0, -1, 1]
    Dx = [-1, 1, 0, 0]
    mapping_inv_x = [0]
    mapping_inv_y = [0]
    for i in range(N):
        y1, y2, x = ABCDEF[i]
        mapping_inv_x.append(x)
        mapping_inv_y.append(y1)
        mapping_inv_y.append(y2)
    for i in range(N, N+M):
        y, x1, x2 = ABCDEF[i]
        mapping_inv_x.append(x1)
        mapping_inv_x.append(x2)
        mapping_inv_y.append(y)
    mapping_inv_y = sorted(set(mapping_inv_y))
    mapping_inv_x = sorted(set(mapping_inv_x))
    H = len(mapping_inv_y) + 1
    W = len(mapping_inv_x) + 1
    E = np.ones((H, W, 4), dtype=np.int8)
    #mapping_y = {v: i for i, v in enumerate(mapping_inv_y, 1)}
    #mapping_x = {v: i for i, v in enumerate(mapping_inv_x, 1)}
    mapping_y = {}
    for i, v in enumerate(mapping_inv_y, 1):
        mapping_y[v] = i
    mapping_x = {}
    for i, v in enumerate(mapping_inv_x, 1):
        mapping_x[v] = i
    for i in range(N):
        y1, y2, x = ABCDEF[i]
        y1 = mapping_y[y1]
        y2 = mapping_y[y2]
        x = mapping_x[x]
        for y in range(y1, y2):
            E[y, x, L] = 0
            E[y, x-1, R] = 0
    for i in range(N, N+M):
        y, x1, x2 = ABCDEF[i]
        y = mapping_y[y]
        x1 = mapping_x[x1]
        x2 = mapping_x[x2]
        for x in range(x1, x2):
            E[y, x, U] = 0
            E[y-1, x, D] = 0
    Diff_x = np.diff(np.array(mapping_inv_x))
    Diff_y = np.diff(np.array(mapping_inv_y))
    Area = np.empty((H, W), dtype=np.int64)
    Area[1:-1, 1:-1] = Diff_y.reshape(-1, 1) * Diff_x
    Closed = np.zeros((H, W), dtype=np.int8)
    y, x = mapping_y[0], mapping_x[0]
    Closed[y, x] = 1
    ans = 0
    stack = [(y, x)]
    while stack:
        vy, vx = stack.pop()
        if vy==0 or vy==H-1 or vx==0 or vx==W-1:
            print("INF")
            return
        ans += Area[vy, vx]
        for direction in [L, R, U, D]:
            if E[vy, vx, direction]:
                uy, ux = vy + Dy[direction], vx + Dx[direction]
                if not Closed[uy, ux]:
                    stack.append((uy, ux))
                    Closed[uy, ux] = 1
    print(ans)

numba_compile([
    [solve, "(i8,i8,i8[:,:])"],
])

def main():
    N, M = map(int, sys.stdin.buffer.readline().split())
    ABCDEF = np.array(sys.stdin.buffer.read().split(), dtype=np.int64).reshape(-1, 3)
    solve(N, M, ABCDEF)

main()

Submission status: Accepted

Solution code:
n,m=map(int,input().split())
def hashh(x,y,f):
    return (x*3000+y)*2+f
abc_l=[list(map(int,input().split()))for _ in range(n)]
def_l=[list(map(int,input().split()))for _ in range(m)]
x=[0]
y=[0]
for a,b,c in abc_l:
    x.append(a)
    x.append(b)
    y.append(c)
for d,e,f in def_l:
    x.append(d)
    y.append(e)
    y.append(f)
x=sorted(list(set(x)))
y=sorted(list(set(y)))
h=len(x)+1
w=len(y)+1
dicx={}
dicy={}
for i in range(len(x)):dicx[x[i]]=i
for i in range(len(y)):dicy[y[i]]=i
grid=[[0]*w for _ in range(h)]
dont=set()
for a,b,c in abc_l:
    for i in range(dicx[a],dicx[b]):
        dont.add(hashh(i+1,dicy[c],1))
for d,e,f in def_l:
    for j in range(dicy[e],dicy[f]):
        dont.add(hashh(dicx[d],j+1,0))
if dicx[0]==0 or dicx[0]==h-1 or dicy[0]==0 or dicy[0]==w-1:
    exit(print("INF"))
stack=[(dicx[0],dicy[0])]
grid[dicx[0]][dicy[0]]=1
ans=0
for sx,sy in stack:
    ans+=(x[sx]-x[sx-1])*(y[sy]-y[sy-1])
    for dx,dy in ((-1,0),(1,0),(0,-1),(0,1)):
        tx=sx+dx
        ty=sy+dy
        if grid[tx][ty]:continue
        if hashh(min(sx,tx),min(sy,ty),1 if sx==tx else 0) in dont:continue
        if tx==0 or tx==h-1 or ty==0 or ty==w-1:
            exit(print("INF"))
        grid[tx][ty]=1
        stack.append((tx,ty))
print(ans)