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.

Solution (Python):
import sys
from typing import Iterable, Tuple, Union

class nd (object):
	getter = (
		lambda a, i: a,
		lambda a, i: a[i[0]],
		lambda a, i: a[i[0]][i[1]],
		lambda a, i: a[i[0]][i[1]][i[2]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]][i[4]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]][i[4]][i[5]],
	)
	class _setter (object):
		def __getitem__(self, n : int):
			setter_getter = nd.getter[n-1]
			def setter(a, i, v):
				setter_getter(a, i[:-1])[i[-1]] = v
			return setter
	setter = _setter()
	initializer = (
		lambda s, v: [v] * s,
		lambda s, v: [v] * s[0],
		lambda s, v: [[v] * s[1] for _ in range(s[0])],
		lambda s, v: [[[v] * s[2] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[v] * s[3] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[[v] * s[4] for _ in range(s[3])] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[[[v] * s[5] for _ in range(s[4])] for _ in range(s[3])] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
	)
	shape_getter = (
		lambda a: len(a),
		lambda a: (len(a),),
		lambda a: (len(a), len(a[0])),
		lambda a: (len(a), len(a[0]), len(a[0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0]), len(a[0][0][0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0]), len(a[0][0][0][0]), len(a[0][0][0][0][0])),
	)
	indices_iterator = (
		lambda s: iter(range(s)),
		lambda s: ((i,) for i in range(s[0])),
		lambda s: ((i, j) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l, m) for m in range(s[4]) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l, m, n) for n in range(s[5]) for m in range(s[4]) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
	)
	iterable_product = (
		lambda s: iter(s),
		lambda s: ((i,) for i in s[0]),
		lambda s: ((i, j) for j in s[1] for i in s[0]),
		lambda s: ((i, j, k) for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l) for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l, m) for m in s[4] for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l, m, n) for n in s[5] for m in s[4] for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
	)
	
	@classmethod
	def full(cls, fill_value, shape : Union[int, Tuple[int], Iterable[int]]):
		if isinstance(shape, int):
			return cls.initializer[0](shape, fill_value)
		elif not isinstance(shape, tuple):
			shape = tuple(shape)
		return cls.initializer[len(shape)](shape, fill_value)
	
	@classmethod
	def fromiter(cls, iterable : Iterable, ndim=1):
		if ndim == 1:
			return list(iterable)
		else:
			return list(map(cls.fromiter, iterable))
	
	@classmethod
	def nones(cls, shape : Union[int, Tuple[int], Iterable[int]]):
		return cls.full(None, shape)
	
	@classmethod
	def zeros(cls, shape : Union[int, Tuple[int], Iterable[int]], type=int):
		return cls.full(type(0), shape)
	
	@classmethod
	def ones(cls, shape : Union[int, Tuple[int], Iterable[int]], type=int):
		return cls.full(type(1), shape)
	
	class _range (object):
		def __getitem__(self, shape : Union[int, slice, Tuple[Union[int, slice]]]):
			if isinstance(shape, int):
				return iter(range(shape))
			elif isinstance(shape, slice):
				return iter(range(shape.stop)[shape])
			else:
				shape = tuple(range(s.stop)[s] for s in shape)
				return nd.iterable_product[len(shape)](shape)
		def __call__(self, shape : Union[int, slice, Tuple[Union[int, slice]]]):
			return self[shape]
	range = _range()



def bytes_to_str(x : bytes):
	return x.decode('utf-8')

def inputs(func=bytes_to_str, sep=None, maxsplit=-1):
	return map(func, sys.stdin.buffer.readline().split(sep=sep, maxsplit=maxsplit))

def inputs_1d(func=bytes_to_str, **kwargs):
	return nd.fromiter(inputs(func, **kwargs))

def inputs_2d(nrows : int, func=bytes_to_str, **kwargs):
	return nd.fromiter(
		(inputs(func, **kwargs) for _ in range(nrows)),
		ndim=2
	)

def inputs_2d_T(nrows : int, func=bytes_to_str, **kwargs):
	return nd.fromiter(
		zip(*(inputs(func, **kwargs) for _ in range(nrows))),
		ndim=2
	)

from typing import Optional


class DepthFirstSearch (object):
	__slots__ = [
		'shape',
		'pushed',
		'_stack',
		'_getter',
		'_setter'
	]
	
	def __init__(self, shape : Union[int, Iterable[int]]):
		self.shape = (shape,) if isinstance(shape, int) else tuple(shape)
		self.pushed = nd.zeros(self.shape, type=bool)
		self._stack = []
		self._getter = nd.getter[len(self.shape)]
		self._setter = nd.setter[len(self.shape)]
	
	def push(self, position : Tuple[int]):
		if not self._getter(self.pushed, position):
			self._setter(self.pushed, position, True)
			self._stack.append(position)
	
	def peek(self) -> Optional[Tuple[int]]:
		return self._stack[-1] if self._stack else None
	
	def pop(self) -> Optional[Tuple[int]]:
		return self._stack.pop() if self._stack else None
	
	def __bool__(self):
		return bool(self._stack)

DFS = DepthFirstSearch

from bisect import bisect_left, bisect_right
from collections import deque


N, M = inputs(int)
A, B, C = inputs_2d_T(N, int)
D, E, F = inputs_2d_T(M, int)
xs = sorted(set(C))
ys = sorted(set(D))

x_guard = nd.zeros((len(xs)+1, len(ys)+1), type=bool)
y_guard = nd.zeros((len(xs)+1, len(ys)+1), type=bool)

for a, b, c in zip(A, B, C):
	c = bisect_right(xs, c)
	a = bisect_left(ys, a) + 1
	b = bisect_right(ys, b)
	for y in range(a, b):
		x_guard[c][y] = True

for d, e, f in zip(D, E, F):
	d = bisect_right(ys, d)
	e = bisect_left(xs, e) + 1
	f = bisect_right(xs, f)
	for x in range(e, f):
		y_guard[x][d] = True

cow = (
	bisect_right(xs, 0),
	bisect_right(ys, 0)
)

bfs = DepthFirstSearch(shape=(len(xs)+1, len(ys)+1))
bfs.push(cow)

area = 0
while bfs:
	xi, yi = bfs.pop()
	
	if 0 < xi < len(xs) and 0 < yi < len(ys):
		area += (xs[xi] - xs[xi-1]) * (ys[yi] - ys[yi-1])
		if not x_guard[xi][yi]:
			bfs.push((xi-1, yi))
		if not x_guard[xi+1][yi]:
			bfs.push((xi+1, yi))
		if not y_guard[xi][yi]:
			bfs.push((xi, yi-1))
		if not y_guard[xi][yi+1]:
			bfs.push((xi, yi+1))
	else:
		area = 'INF'
		break

print(area)

Solution (Python):

import sys
import numpy as np
from numba import njit


def main():
    N, M = map(int, sys.stdin.buffer.readline().split())
    LineData = np.int64(sys.stdin.buffer.read().split())

    INF = 10**9 + 1

    LineData = LineData.reshape(-1, 3)
    A, B, C = LineData[:N].T
    D, E, F = LineData[N:].T
    X = np.unique(np.concatenate([D, [-INF, 0, INF]]))
    Y = np.unique(np.concatenate([C, [-INF, 0, INF]]))
    A = np.searchsorted(X, A)
    B = np.searchsorted(X, B, 'right') - 1
    C = np.searchsorted(Y, C)
    D = np.searchsorted(X, D)
    E = np.searchsorted(Y, E)
    F = np.searchsorted(Y, F, 'right') - 1

    area = cal_area(A, B, C, D, E, F, X, Y)

    if area == 0:
        print("INF")
    else:
        print(area)


@njit
def cal_area(A, B, C, D, E, F, X, Y):
    LenX = len(X)
    LenY = len(Y)

    LineX = [[False] * LenY for _ in range(LenX)]
    LineY = [[False] * LenY for _ in range(LenX)]

    for x1, x2, y in zip(A, B, C):
        for x in range(x1, x2):
            LineY[x][y] = True

    for x, y1, y2 in zip(D, E, F):
        for y in range(y1, y2):
            LineX[x][y] = True
    
    visit = [[False] * LenY for _ in range(LenX)]
    x = np.searchsorted(X, 0, 'right') - 1
    y = np.searchsorted(Y, 0, 'right') - 1
    visit[x][y] = True
    area = 0
    queue = [(x, y)]

    while queue:
        x, y = queue.pop()

        if x == 0 or x == LenX - 1 or y == 0 or y == LenY - 1:
            area = 0
            break
        
        area += (X[x + 1] - X[x]) * (Y[y + 1] - Y[y])

        if not LineX[x][y] and not visit[x - 1][y]:
            visit[x - 1][y] = True
            queue.append((x - 1, y))
        if not LineY[x][y] and not visit[x][y - 1]:
            visit[x][y - 1] = True
            queue.append((x, y - 1))
        if not LineX[x + 1][y] and not visit[x + 1][y]:
            visit[x + 1][y] = True
            queue.append((x + 1, y))
        if not LineY[x][y + 1] and not visit[x][y + 1]:
            visit[x][y + 1] = True
            queue.append((x, y + 1))

    return area


if __name__ == '__main__':
	main()

sys.exit()

Solution (Python):
import bisect
INF = 10**9 + 1
n, m = map(int, input().split())
X, Y = [-INF, 0, INF], [-INF, 0, INF]
ABC, DEF = [], []
for i in range(n):
    a, b, c = map(int, input().split())
    ABC.append((a, b, c))
    X.append(a)
    X.append(b)
    Y.append(c)
    Y.append(c)
for j in range(m):
    d, e, f = map(int, input().split())
    DEF.append((d, e, f))
    X.append(d)
    X.append(d)
    Y.append(e)
    Y.append(f)
X.sort()
Y.sort()
V = [[0 for y in Y] for x in X]
for a, b, c in ABC:
    j = bisect.bisect_left(Y, c)
    ia = bisect.bisect_left(X, a)
    ib = bisect.bisect_left(X, b)
    for i in range(ia, ib):
        V[i][j] = 1
for d, e, f in DEF:
    i = bisect.bisect_left(X, d)
    je = bisect.bisect_left(Y, e)
    jf = bisect.bisect_left(Y, f)
    for j in range(je, jf):
        V[i][j] = 1
i = bisect.bisect_left(X, 0)
j = bisect.bisect_left(Y, 0)
Q = [(i, j)]
V[i][j] = 1
ans = 0
while Q:
    i, j = Q.pop()
    ans += (X[i + 1] - X[i]) * (Y[j + 1] - Y[j])
    for di, dj in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
        if 0 < i + di < len(X) - 1 and 0 < j + dj < len(Y) - 1:
            if V[i + di][j + dj] == 0:
                V[i + di][j + dj] = 1
                Q.append((i + di, j + dj))
        else:
            print('INF')
            exit()
print(ans)

Solution (Python):
import sys
from typing import Iterable, Tuple, Union

class nd (object):
	getter = (
		lambda a, i: a,
		lambda a, i: a[i[0]],
		lambda a, i: a[i[0]][i[1]],
		lambda a, i: a[i[0]][i[1]][i[2]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]][i[4]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]][i[4]][i[5]],
	)
	class _setter (object):
		def __getitem__(self, n : int):
			setter_getter = nd.getter[n-1]
			def setter(a, i, v):
				setter_getter(a, i[:-1])[i[-1]] = v
			return setter
	setter = _setter()
	initializer = (
		lambda s, v: [v] * s,
		lambda s, v: [v] * s[0],
		lambda s, v: [[v] * s[1] for _ in range(s[0])],
		lambda s, v: [[[v] * s[2] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[v] * s[3] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[[v] * s[4] for _ in range(s[3])] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[[[v] * s[5] for _ in range(s[4])] for _ in range(s[3])] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
	)
	shape_getter = (
		lambda a: len(a),
		lambda a: (len(a),),
		lambda a: (len(a), len(a[0])),
		lambda a: (len(a), len(a[0]), len(a[0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0]), len(a[0][0][0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0]), len(a[0][0][0][0]), len(a[0][0][0][0][0])),
	)
	indices_iterator = (
		lambda s: iter(range(s)),
		lambda s: ((i,) for i in range(s[0])),
		lambda s: ((i, j) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l, m) for m in range(s[4]) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l, m, n) for n in range(s[5]) for m in range(s[4]) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
	)
	iterable_product = (
		lambda s: iter(s),
		lambda s: ((i,) for i in s[0]),
		lambda s: ((i, j) for j in s[1] for i in s[0]),
		lambda s: ((i, j, k) for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l) for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l, m) for m in s[4] for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l, m, n) for n in s[5] for m in s[4] for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
	)
	
	@classmethod
	def full(cls, fill_value, shape : Union[int, Tuple[int], Iterable[int]]):
		if isinstance(shape, int):
			return cls.initializer[0](shape, fill_value)
		elif not isinstance(shape, tuple):
			shape = tuple(shape)
		return cls.initializer[len(shape)](shape, fill_value)
	
	@classmethod
	def fromiter(cls, iterable : Iterable, ndim=1):
		if ndim == 1:
			return list(iterable)
		else:
			return list(map(cls.fromiter, iterable))
	
	@classmethod
	def nones(cls, shape : Union[int, Tuple[int], Iterable[int]]):
		return cls.full(None, shape)
	
	@classmethod
	def zeros(cls, shape : Union[int, Tuple[int], Iterable[int]], type=int):
		return cls.full(type(0), shape)
	
	@classmethod
	def ones(cls, shape : Union[int, Tuple[int], Iterable[int]], type=int):
		return cls.full(type(1), shape)
	
	class _range (object):
		def __getitem__(self, shape : Union[int, slice, Tuple[Union[int, slice]]]):
			if isinstance(shape, int):
				return iter(range(shape))
			elif isinstance(shape, slice):
				return iter(range(shape.stop)[shape])
			else:
				shape = tuple(range(s.stop)[s] for s in shape)
				return nd.iterable_product[len(shape)](shape)
		def __call__(self, shape : Union[int, slice, Tuple[Union[int, slice]]]):
			return self[shape]
	range = _range()


def bytes_to_str(x : bytes):
	return x.decode('utf-8')

def inputs(func=bytes_to_str, sep=None, maxsplit=-1):
	return map(func, sys.stdin.buffer.readline().split(sep=sep, maxsplit=maxsplit))

def inputs_1d(func=bytes_to_str, **kwargs):
	return nd(inputs(func, **kwargs))

def inputs_2d(nrows : int, func=bytes_to_str, **kwargs):
	return nd.fromiter(
		(inputs(func, **kwargs) for _ in range(nrows)),
		ndim=2
	)

def inputs_2d_T(nrows : int, func=bytes_to_str, **kwargs):
	return nd.fromiter(
		zip(*(inputs(func, **kwargs) for _ in range(nrows))),
		ndim=2
	)

from collections import deque
from typing import Optional


class BreadthFirstSearch (object):
	__slots__ = [
		'shape',
		'pushed',
		'_deque',
		'_getter',
		'_setter'
	]
	
	def __init__(self, shape : Union[int, Iterable[int]]):
		self.shape = (shape,) if isinstance(shape, int) else tuple(shape)
		self.pushed = nd.zeros(self.shape, type=bool)
		self._deque = deque()
		self._getter = nd.getter[len(self.shape)]
		self._setter = nd.setter[len(self.shape)]
	
	def push(self, position : Tuple[int]):
		if not self._getter(self.pushed, position):
			self._setter(self.pushed, position, True)
			self._deque.append(position)
	
	def peek(self) -> Optional[Tuple[int]]:
		return self._deque[0] if self._deque else None
	
	def pop(self) -> Optional[Tuple[int]]:
		return self._deque.popleft() if self._deque else None
	
	def __bool__(self):
		return bool(self._deque)

from bisect import bisect_left, bisect_right


N, M = inputs(int)
A, B, C = inputs_2d_T(N, int)
D, E, F = inputs_2d_T(M, int)
xs = sorted(set(C))
ys = sorted(set(D))

x_guard = nd.zeros((len(xs)+1, len(ys)+1), type=bool)
y_guard = nd.zeros((len(xs)+1, len(ys)+1), type=bool)

for a, b, c in zip(A, B, C):
	c = bisect_right(xs, c)
	a = bisect_left(ys, a) + 1
	b = bisect_right(ys, b)
	for y in range(a, b):
		x_guard[c][y] = True

for d, e, f in zip(D, E, F):
	d = bisect_right(ys, d)
	e = bisect_left(xs, e) + 1
	f = bisect_right(xs, f)
	for x in range(e, f):
		y_guard[x][d] = True

cow = (
	bisect_right(xs, 0),
	bisect_right(ys, 0)
)

bfs = BreadthFirstSearch(shape=(len(xs)+1, len(ys)+1))
bfs.push(cow)

area = 0
while bfs:
	xi, yi = bfs.pop()
	
	if 0 < xi < len(xs) and 0 < yi < len(ys):
		area += (xs[xi] - xs[xi-1]) * (ys[yi] - ys[yi-1])
		if not x_guard[xi][yi]:
			bfs.push((xi-1, yi))
		if not x_guard[xi+1][yi]:
			bfs.push((xi+1, yi))
		if not y_guard[xi][yi]:
			bfs.push((xi, yi-1))
		if not y_guard[xi][yi+1]:
			bfs.push((xi, yi+1))
	else:
		area = 'INF'
		break

print(area)

Solution (Python):
import sys
from typing import Iterable, Tuple, Union

class nd (object):
	getter = (
		lambda a, i: a,
		lambda a, i: a[i[0]],
		lambda a, i: a[i[0]][i[1]],
		lambda a, i: a[i[0]][i[1]][i[2]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]][i[4]],
		lambda a, i: a[i[0]][i[1]][i[2]][i[3]][i[4]][i[5]],
	)
	initializer = (
		lambda s, v: [v] * s,
		lambda s, v: [v] * s[0],
		lambda s, v: [[v] * s[1] for _ in range(s[0])],
		lambda s, v: [[[v] * s[2] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[v] * s[3] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[[v] * s[4] for _ in range(s[3])] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
		lambda s, v: [[[[[[v] * s[5] for _ in range(s[4])] for _ in range(s[3])] for _ in range(s[2])] for _ in range(s[1])] for _ in range(s[0])],
	)
	shape_getter = (
		lambda a: len(a),
		lambda a: (len(a),),
		lambda a: (len(a), len(a[0])),
		lambda a: (len(a), len(a[0]), len(a[0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0]), len(a[0][0][0][0])),
		lambda a: (len(a), len(a[0]), len(a[0][0]), len(a[0][0][0]), len(a[0][0][0][0]), len(a[0][0][0][0][0])),
	)
	indices_iterator = (
		lambda s: iter(range(s)),
		lambda s: ((i,) for i in range(s[0])),
		lambda s: ((i, j) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l, m) for m in range(s[4]) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
		lambda s: ((i, j, k, l, m, n) for n in range(s[5]) for m in range(s[4]) for l in range(s[3]) for k in range(s[2]) for j in range(s[1]) for i in range(s[0])),
	)
	iterable_product = (
		lambda s: iter(s),
		lambda s: ((i,) for i in s[0]),
		lambda s: ((i, j) for j in s[1] for i in s[0]),
		lambda s: ((i, j, k) for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l) for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l, m) for m in s[4] for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
		lambda s: ((i, j, k, l, m, n) for n in s[5] for m in s[4] for l in s[3] for k in s[2] for j in s[1] for i in s[0]),
	)
	
	@classmethod
	def full(cls, fill_value, shape : Union[int, Tuple[int], Iterable[int]]):
		if isinstance(shape, int):
			return cls.initializer[0](shape, fill_value)
		elif not isinstance(shape, tuple):
			shape = tuple(shape)
		return cls.initializer[len(shape)](shape, fill_value)
	
	@classmethod
	def fromiter(cls, iterable : Iterable, ndim=1):
		if ndim == 1:
			return list(iterable)
		else:
			return list(map(cls.fromiter, iterable))
	
	@classmethod
	def nones(cls, shape : Union[int, Tuple[int], Iterable[int]]):
		return cls.full(None, shape)
	
	@classmethod
	def zeros(cls, shape : Union[int, Tuple[int], Iterable[int]], type=int):
		return cls.full(type(0), shape)
	
	@classmethod
	def ones(cls, shape : Union[int, Tuple[int], Iterable[int]], type=int):
		return cls.full(type(1), shape)
	
	class _range (object):
		def __getitem__(self, shape : Union[int, slice, Tuple[Union[int, slice]]]):
			if isinstance(shape, int):
				return iter(range(shape))
			elif isinstance(shape, slice):
				return iter(range(shape.stop)[shape])
			else:
				shape = tuple(range(s.stop)[s] for s in shape)
				return nd.iterable_product[len(shape)](shape)
		def __call__(self, shape : Union[int, slice, Tuple[Union[int, slice]]]):
			return self[shape]
	range = _range()


def bytes_to_str(x : bytes):
	return x.decode('utf-8')

def inputs(func=bytes_to_str, sep=None, maxsplit=-1):
	return map(func, sys.stdin.buffer.readline().split(sep=sep, maxsplit=maxsplit))

def inputs_1d(func=bytes_to_str, **kwargs):
	return nd(inputs(func, **kwargs))

def inputs_2d(nrows : int, func=bytes_to_str, **kwargs):
	return nd.fromiter(
		(inputs(func, **kwargs) for _ in range(nrows)),
		ndim=2
	)

def inputs_2d_T(nrows : int, func=bytes_to_str, **kwargs):
	return nd.fromiter(
		zip(*(inputs(func, **kwargs) for _ in range(nrows))),
		ndim=2
	)

from collections import deque
from typing import Optional


class BreadthFirstSearch (object):
	def __init__(self, shape : Union[int, Iterable[int]]):
		self.shape = (shape,) if isinstance(shape, int) else tuple(shape)
		self.pushed = nd.zeros(self.shape, type=bool)
		self._deque = deque()
		self._getter_getter = nd.getter[len(self.shape)]
		self._setter_getter = nd.getter[len(self.shape) - 1]
	
	def push(self, position : Tuple[int]):
		if not self._getter_getter(self.pushed, position):
			self._setter_getter(self.pushed, position[:-1])[position[-1]] = True
			self._deque.append(position)
	
	def peek(self) -> Optional[Tuple[int]]:
		return self._deque[0] if self._deque else None
	
	def pop(self) -> Optional[Tuple[int]]:
		return self._deque.popleft() if self._deque else None
	
	def __bool__(self):
		return bool(self._deque)

from bisect import bisect_left, bisect_right


N, M = inputs(int)
A, B, C = inputs_2d_T(N, int)
D, E, F = inputs_2d_T(M, int)
xs = sorted(set(C))
ys = sorted(set(D))

x_guard = nd.zeros((len(xs)+1, len(ys)+1), type=bool)
y_guard = nd.zeros((len(xs)+1, len(ys)+1), type=bool)

for a, b, c in zip(A, B, C):
	c = bisect_right(xs, c)
	a = bisect_left(ys, a) + 1
	b = bisect_right(ys, b)
	for y in range(a, b):
		x_guard[c][y] = True

for d, e, f in zip(D, E, F):
	d = bisect_right(ys, d)
	e = bisect_left(xs, e) + 1
	f = bisect_right(xs, f)
	for x in range(e, f):
		y_guard[x][d] = True

cow = (
	bisect_right(xs, 0),
	bisect_right(ys, 0)
)

bfs = BreadthFirstSearch(shape=(len(xs)+1, len(ys)+1))
bfs.push(cow)

area = 0
while bfs:
	xi, yi = bfs.pop()
	
	if 0 < xi < len(xs) and 0 < yi < len(ys):
		area += (xs[xi] - xs[xi-1]) * (ys[yi] - ys[yi-1])
		if not x_guard[xi][yi]:
			bfs.push((xi-1, yi))
		if not x_guard[xi+1][yi]:
			bfs.push((xi+1, yi))
		if not y_guard[xi][yi]:
			bfs.push((xi, yi-1))
		if not y_guard[xi][yi+1]:
			bfs.push((xi, yi+1))
	else:
		area = 'INF'
		break

print(area)