AtCoder Beginner Contest 168 - . (Single Dot)

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-----
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

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

Difficulty: MEDIUM_HARD

Starter code:

Solutions:
import sys
input = lambda : sys.stdin.readline().rstrip()
sys.setrecursionlimit(max(1000, 10 ** 9))
write = lambda x: sys.stdout.write(x + '\n')
(n, m) = map(int, input().split())
lx = [None] * n
ly = [None] * m
sx = set([-10 ** 10, 0, 10 ** 10])
sy = set([-10 ** 10, 0, 10 ** 10])
ix = 0
iy = 0
for i in range(n):
	t = tuple(map(int, input().split()))
	lx[i] = t
	sx.add(t[0])
	sx.add(t[1])
	sy.add(t[2])
for i in range(m):
	t = tuple(map(int, input().split()))
	ly[i] = t
	sx.add(t[0])
	sy.add(t[1])
	sy.add(t[2])
xs = list(sx)
ys = list(sy)
xs.sort()
ys.sort()
wx = len(xs) * 2
wy = len(ys) * 2
bs = [[1] * wy for _ in range(wx)]
import bisect
for (i, (x0, x1, y)) in enumerate(lx):
	ix0 = bisect.bisect_left(xs, x0) * 2
	ix1 = bisect.bisect_left(xs, x1) * 2
	iy = bisect.bisect_left(ys, y) * 2
	for ii in range(ix0 + 1, ix1, 2):
		bs[ii][iy] = -1
for (i, (x, y0, y1)) in enumerate(ly):
	ix = bisect.bisect_left(xs, x) * 2
	iy0 = bisect.bisect_left(ys, y0) * 2
	iy1 = bisect.bisect_left(ys, y1) * 2
	for ii in range(iy0 + 1, iy1, 2):
		bs[ix][ii] = -1
xx = bisect.bisect_left(xs, 0) * 2 + 1
yy = bisect.bisect_left(ys, 0) * 2 + 1
s = [(xx, yy)]
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
ans = 0
end = False
while s:
	(ix, iy) = s.pop()
	for (x, y) in zip(dx, dy):
		ixx = ix + x
		iyy = iy + y
		if bs[ixx][iyy] != 1:
			continue
		ixx += x
		iyy += y
		if bs[ixx][iyy] != 1:
			continue
		if ixx < 0 or ixx >= wx - 1 or iyy < 0 or (iyy >= wy - 1):
			print('INF')
			s = []
			end = True
			break
		bs[ixx][iyy] = 2
		ans += (xs[ixx // 2 + 1] - xs[ixx // 2]) * (ys[iyy // 2 + 1] - ys[iyy // 2])
		s.append((ixx, iyy))
if not end:
	print(ans)


(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
movable = [(-1, 0), (1, 0), (0, -1), (0, 1)]
blocked = {}
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(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(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))
visited = [0] * max_X * max_Y

def get_visited(x, y):
	return visited[x * max_Y + y]

def set_visited(x, y):
	visited[x * max_Y + y] = True
to_visit = [(X[0], Y[0])]
while 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)


(n, m) = map(int, input().split())
xti = {}
yti = {}
xti[0] = -1
yti[0] = -1
lvs = []
for i in range(n):
	(a, b, c) = map(int, input().split())
	yti[a] = -1
	yti[b] = -1
	xti[c] = -1
	lvs.append((a, b, c))
lhs = []
for i in range(m):
	(d, e, f) = map(int, input().split())
	yti[d] = -1
	xti[e] = -1
	xti[f] = -1
	lhs.append((d, e, f))
xs = sorted(xti.keys())
for (i, x) in enumerate(xs):
	xti[x] = i
ys = sorted(yti.keys())
for (i, y) in enumerate(ys):
	yti[y] = i
xsl = len(xs) * 2
ysl = len(ys) * 2
fi = [[0 for x in range(xsl)] for y in range(ysl)]
for (a, b, c) in lvs:
	x = xti[c] * 2
	for y in range(yti[a] * 2, yti[b] * 2 + 1):
		fi[y][x] = 2
for (d, e, f) in lhs:
	y = yti[d] * 2
	for x in range(xti[e] * 2, xti[f] * 2 + 1):
		fi[y][x] = 2
(cx, cy) = (xti[0] * 2 + 1, yti[0] * 2 + 1)
if cx < 0 or cx >= xsl - 1 or cy < 0 or (cy >= ysl - 1):
	print('INF')
	exit()
q = []
q.append((cx, cy))
fi[cy][cx] = 1
s = (xs[(cx + 1) // 2] - xs[cx // 2]) * (ys[(cy + 1) // 2] - ys[cy // 2])
dxs = [0, 1, 0, -1]
dys = [1, 0, -1, 0]
while q:
	(x, y) = q.pop(-1)
	for i in range(4):
		cx = x + dxs[i] * 2
		cy = y + dys[i] * 2
		if fi[cy][cx] != 0:
			continue
		pcx = x + dxs[i]
		pcy = y + dys[i]
		if fi[pcy][pcx] == 2:
			continue
		if cx < 0 or cx >= xsl - 1 or cy < 0 or (cy >= ysl - 1):
			print('INF')
			exit()
		fi[cy][cx] = 1
		s += (xs[(cx + 1) // 2] - xs[cx // 2]) * (ys[(cy + 1) // 2] - ys[cy // 2])
		q.append((cx, cy))
print(s)


import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
(n, m) = map(int, readline().split())
data = list(map(int, read().split()))
point = [{0, 10 ** 9, -1 * 10 ** 9} for _ in range(2)]
dic_en = [{} for _ in range(2)]
dic_de = [{} for _ in range(2)]
it = iter(data[:3 * n])
for (a, b, c) in zip(it, it, it):
	point[0].add(a)
	point[0].add(b)
	point[1].add(c)
it = iter(data[3 * n:])
for (d, e, f) in zip(it, it, it):
	point[0].add(d)
	point[1].add(e)
	point[1].add(f)
for (i, p) in enumerate(point):
	p = sorted(list(p))
	for (after, before) in enumerate(p):
		dic_en[i][before] = after
		dic_de[i][after] = before
len_x = len(point[0])
len_y = len(point[1])
wall_x = [[0] * (len_y - 1) for _ in range(len_x)]
wall_y = [[0] * len_y for _ in range(len_x - 1)]
it = iter(data[:3 * n])
for (a, b, c) in zip(it, it, it):
	(a, b, c) = (dic_en[0][a], dic_en[0][b], dic_en[1][c])
	wall_y[a][c] += 1
	if b != len_x - 1:
		wall_y[b][c] -= 1
it = iter(data[3 * n:])
for (d, e, f) in zip(it, it, it):
	(d, e, f) = (dic_en[0][d], dic_en[1][e], dic_en[1][f])
	wall_x[d][e] += 1
	if f != len_y - 1:
		wall_x[d][f] -= 1
for i in range(len_x):
	for j in range(1, len_y - 1):
		wall_x[i][j] += wall_x[i][j - 1]
for i in range(1, len_x - 1):
	for j in range(len_y):
		wall_y[i][j] += wall_y[i - 1][j]
start = (dic_en[0][0], dic_en[1][0])
area = [[0] * (len_y - 1) for _ in range(len_x - 1)]
ans = 0
stack = [start]
(i, j) = start
area[i][j] = 1
while stack:
	(i, j) = stack.pop()
	ans += (dic_de[0][i + 1] - dic_de[0][i]) * (dic_de[1][j + 1] - dic_de[1][j])
	if wall_x[i + 1][j] == 0:
		if i == len_x - 2:
			print('INF')
			exit()
		if area[i + 1][j] == 0:
			stack.append((i + 1, j))
			area[i + 1][j] = 1
	if wall_x[i][j] == 0:
		if i == 0:
			print('INF')
			exit()
		if area[i - 1][j] == 0:
			stack.append((i - 1, j))
			area[i - 1][j] = 1
	if wall_y[i][j + 1] == 0:
		if j == len_y - 2:
			print('INF')
			exit()
		if area[i][j + 1] == 0:
			stack.append((i, j + 1))
			area[i][j + 1] = 1
	if wall_y[i][j] == 0:
		if j == 0:
			print('INF')
			exit()
		if area[i][j - 1] == 0:
			stack.append((i, j - 1))
			area[i][j - 1] = 1
print(ans)


def f_single_dot():
	import sys
	from collections import deque
	input = sys.stdin.readline
	(N, M) = [int(i) for i in input().split()]
	(X, Y) = (set([0]), set([0]))
	vertical_lines = []
	for _ in range(N):
		(a, b, grid) = map(int, input().split())
		vertical_lines.append((a, b, grid))
		X |= {a, b}
		Y |= {grid}
	horizontal_lines = []
	for _ in range(M):
		(d, e, f) = map(int, input().split())
		horizontal_lines.append((d, e, f))
		X |= {d}
		Y |= {e, f}
	X = sorted(X)
	Y = sorted(Y)
	(dictx, dicty) = ({n: i * 2 for (i, n) in enumerate(X)}, {n: i * 2 for (i, n) in enumerate(Y)})
	LX = [X[i // 2 + 1] - X[i // 2] if i % 2 else 0 for i in range(len(X) * 2 - 1)]
	LY = [Y[i // 2 + 1] - Y[i // 2] if i % 2 else 0 for i in range(len(Y) * 2 - 1)]
	grid = [[0] * (len(X) * 2 - 1) for _ in range(len(Y) * 2 - 1)]
	for (a, b, c) in vertical_lines:
		(a, b, c) = (dictx[a], dictx[b], dicty[c])
		for x in range(a, b + 1):
			grid[c][x] = 1
	for (d, e, f) in horizontal_lines:
		(d, e, f) = (dictx[d], dicty[e], dicty[f])
		for y in range(e, f + 1):
			grid[y][d] = 1
	que = deque()
	used = [[0] * len(X) * 2 for _ in range(len(Y) * 2)]
	dy = [1, 1, -1, -1]
	dx = [1, -1, 1, -1]
	for k in range(4):
		(nny, nnx) = (dicty[0] + dy[k], dictx[0] + dx[k])
		if 1 <= nny < len(Y) * 2 - 1 and 1 <= nnx < len(X) * 2 - 1:
			que.append((nny, nnx))
			used[nny][nnx] = 1
	ans = 0
	dy = [1, 0, -1, 0]
	dx = [0, 1, 0, -1]
	while que:
		(y, x) = que.popleft()
		if y % 2 and x % 2:
			ans += LY[y] * LX[x]
		for k in range(4):
			(ny, nx) = (y + dy[k], x + dx[k])
			(nny, nnx) = (ny + dy[k], nx + dx[k])
			if grid[ny][nx] == 0:
				if nny < 0 or nny >= len(Y) * 2 - 1 or nnx < 0 or (nnx >= len(X) * 2 - 1):
					return 'INF'
				if not used[nny][nnx]:
					que.append((nny, nnx))
					used[nny][nnx] = 1
	return ans
print(f_single_dot())


I = lambda : [int(i) for i in input().split()]
F = 1 << 65
r = range
(n, m) = I()
X = set([0, F, -F])
Y = set(X)
R = [((-F, F), F), ((-F, F), -F)]
H = [(F, (-F, F)), (-F, (-F, F))]
for i in r(n):
	(a, b, c) = I()
	R.append(((a, b), c))
	Y.add(c)
	X.add(a)
	X.add(b)
for i in r(m):
	(a, b, c) = I()
	H.append((a, (b, c)))
	X.add(a)
	Y.add(b)
	Y.add(c)
s = dict(enumerate(sorted(X)))
K = len(s)
t = dict(enumerate(sorted(Y)))
L = len(t)
h = dict(((s[i], i) for i in s))
w = dict(((t[i], i) for i in t))
V = [[0] * -~K for i in r(L + 1)]
U = [i[:] for i in V]
v = [i[:] for i in V]
q = [(h[0], w[0])]
v[w[0]][h[0]] = 1
z = 0
for ((a, b), c) in R:
	U[w[c]][h[a]] += 1
	U[w[c]][h[b]] += -1
for i in r(L + 1):
	for j in r(K):
		U[i][j + 1] += U[i][j]
for (d, (e, f)) in H:
	V[w[e]][h[d]] += 1
	V[w[f]][h[d]] += -1
for j in r(K + 1):
	for i in r(L):
		V[i + 1][j] += V[i][j]
while q:
	(x, y) = q.pop()
	z += (s[x] - s[x + 1]) * (t[y] - t[y + 1])
	for (e, f) in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
		k = 0
		c = x + e
		d = y + f
		if (0 <= c < K) * (0 <= d < L) * v[d][c] == 0:
			k = U[-~f // 2 + y][x] == 0 if f != 0 else V[y][-~e // 2 + x] == 0
		if k:
			q.append((c, d))
			v[d][c] = 1
if z > F:
	z = 'INF'
print(z)


(N, M) = map(int, input().split())
h_lines = {}
v_lines = {}
for _ in range(N):
	(a, b, c) = map(int, input().split())
	if c in v_lines:
		v_lines[c].append((a, b))
	else:
		v_lines[c] = [(a, b)]
for _ in range(M):
	(d, e, f) = map(int, input().split())
	if d in h_lines:
		h_lines[d].append((e, f))
	else:
		h_lines[d] = [(e, f)]
h_lines = list(h_lines.items())
v_lines = list(v_lines.items())
h_lines.sort()
v_lines.sort()
rows = len(v_lines) - 1
cols = len(h_lines) - 1
h_walls = [[False] * rows for _ in range(cols + 1)]
v_walls = [[False] * (rows + 1) for _ in range(cols)]
for (i, (y, l)) in enumerate(h_lines):
	for (x1, x2) in l:
		j = 0
		while j < rows:
			if x1 <= v_lines[j][0]:
				break
			j += 1
		while j < rows:
			if x2 < v_lines[j + 1][0]:
				break
			h_walls[i][j] = True
			j += 1
for (j, (x, l)) in enumerate(v_lines):
	for (y1, y2) in l:
		i = 0
		while i < cols:
			if y1 <= h_lines[i][0]:
				break
			i += 1
		while i < cols:
			if y2 < h_lines[i + 1][0]:
				break
			v_walls[i][j] = True
			i += 1

def find_initial_pos():
	for i in range(cols):
		if h_lines[i][0] <= 0 and 0 <= h_lines[i + 1][0]:
			for j in range(rows):
				if v_lines[j][0] <= 0 and 0 <= v_lines[j + 1][0]:
					return (i, j)
	return None

def calc_area():
	cur = find_initial_pos()
	if cur == None:
		return 'INF'
	stack = [cur]
	area = 0
	visited = [[False] * rows for _ in range(cols)]
	visited[cur[0]][cur[1]] = True
	search = ((1, 0, lambda y, x: not h_walls[y + 1][x]), (-1, 0, lambda y, x: not h_walls[y][x]), (0, 1, lambda y, x: not v_walls[y][x + 1]), (0, -1, lambda y, x: not v_walls[y][x]))
	while stack:
		(y, x) = stack.pop()
		area += (h_lines[y + 1][0] - h_lines[y][0]) * (v_lines[x + 1][0] - v_lines[x][0])
		for (dy, dx, check) in search:
			if check(y, x):
				ny = y + dy
				nx = x + dx
				if nx < 0 or nx >= rows or ny < 0 or (ny >= cols):
					return 'INF'
				if not visited[ny][nx]:
					stack.append((ny, nx))
					visited[ny][nx] = True
	return str(area)
print(calc_area())


I = lambda : map(int, input().split())
F = 1e+21
r = range
(n, m) = I()
f = [-F, F]
X = [0] + f
Y = X[:]
R = [(f, F), (f, -F)]
H = [(F, f), (-F, f)]
for i in r(n):
	(*a, c) = I()
	R += [(a, c)]
	Y += (c,)
	X += a
for i in r(m):
	(a, *b) = I()
	H += [(a, b)]
	X += (a,)
	Y += b

def g(X):
	s = dict(enumerate(sorted(set(X))))
	return ({s[i]: i for i in s}, s, len(s) + 1)
(h, s, K) = g(X)
(w, t, L) = g(Y)
j = lambda : [[0] * -~K for i in r(L + 1)]
V = j()
U = j()
v = j()
for ((a, b), c) in R:
	U[w[c]][h[a]] += 1
	U[w[c]][h[b]] += -1
for (d, (e, f)) in H:
	V[w[e]][h[d]] += 1
	V[w[f]][h[d]] += -1
for i in r(L):
	for j in r(K):
		U[i][j + 1] += U[i][j]
		V[i + 1][j] += V[i][j]
q = [(h[0], w[0])]
v[w[0]][h[0]] = 1
a = 0
while q:
	(x, y) = q.pop()
	a += (s[x] - s[x + 1]) * (t[y] - t[y + 1])
	for (e, f) in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
		c = x + e
		d = y + f
		if 1 - v[d][c] and (U[(f > 0) + y][x] | e == 0) | (V[y][(e > 0) + x] | f == 0):
			q += [(c, d)]
			v[d][c] = 1
print([a, 'INF'][a > F])


import sys
input = sys.stdin.buffer.readline
from collections import deque
(N, M) = map(int, input().split())
X = [-10 ** 9, 0, 10 ** 9]
Y = [-10 ** 9, 0, 10 ** 9]
tate = []
yoko = []
for _ in range(N):
	(a, b, c) = map(int, input().split())
	X.append(a)
	X.append(b)
	Y.append(c)
	tate.append((a, b, c))
for _ in range(M):
	(d, e, f) = map(int, input().split())
	X.append(d)
	Y.append(e)
	Y.append(f)
	yoko.append((d, e, f))
X = sorted(set(X))
Y = sorted(set(Y))
Cx = {val: idx * 2 for (idx, val) in enumerate(X)}
Cy = {val: idx * 2 for (idx, val) in enumerate(Y)}
H = len(X) * 2 - 1
W = len(Y) * 2 - 1
G = [0] * (H * W)
for (a, b, c) in tate:
	j = Cy[c]
	for i in range(Cx[a], Cx[b] + 1):
		G[i * W + j] = -1
for (d, e, f) in yoko:
	i = Cx[d]
	for j in range(Cy[e], Cy[f] + 1):
		G[i * W + j] = -1
for i in range(1, H, 2):
	for j in range(1, W, 2):
		G[i * W + j] = (X[(i + 1) // 2] - X[(i - 1) // 2]) * (Y[(j + 1) // 2] - Y[(j - 1) // 2])
queue = deque([Cx[0] * W + Cy[0]])
visited = [0] * (H * W)
visited[Cx[0] * W + Cy[0]] = 1
res = 0
while queue:
	z = queue.popleft()
	nz = z + W
	if G[nz] != -1 and (not visited[nz]):
		nx = nz // W
		if nx == H - 1:
			print('INF')
			break
		visited[nz] = 1
		res += G[nz]
		queue.append(nz)
	nz = z - W
	if G[nz] != -1 and (not visited[nz]):
		nx = nz // W
		if nx == 0:
			print('INF')
			break
		visited[nz] = 1
		res += G[nz]
		queue.append(nz)
	nz = z + 1
	if G[nz] != -1 and (not visited[nz]):
		ny = nz % W
		if ny == W - 1:
			print('INF')
			break
		visited[nz] = 1
		res += G[nz]
		queue.append(nz)
	nz = z - 1
	if G[nz] != -1 and (not visited[nz]):
		ny = nz % W
		if ny == 0:
			print('INF')
			break
		visited[nz] = 1
		res += G[nz]
		queue.append(nz)
else:
	print(res)


def f_single_dot():
	import sys
	from collections import deque
	input = sys.stdin.readline
	(N, M) = [int(i) for i in input().split()]
	(x_set, y_set) = (set([0]), set([0]))
	vertical_lines = []
	for _ in range(N):
		(a, b, c) = map(int, input().split())
		vertical_lines.append((a, b, c))
		x_set |= {a, b}
		y_set |= {c}
	horizontal_lines = []
	for _ in range(M):
		(d, e, f) = map(int, input().split())
		horizontal_lines.append((d, e, f))
		x_set |= {d}
		y_set |= {e, f}
	x_set = sorted(x_set)
	y_set = sorted(y_set)
	x_encoded = {n: i * 2 for (i, n) in enumerate(x_set)}
	y_encoded = {n: i * 2 for (i, n) in enumerate(y_set)}
	x_length = [x_set[i // 2 + 1] - x_set[i // 2] if i % 2 else 0 for i in range(len(x_set) * 2 - 1)]
	y_length = [y_set[i // 2 + 1] - y_set[i // 2] if i % 2 else 0 for i in range(len(y_set) * 2 - 1)]
	grid = [[0] * (len(x_set) * 2 - 1) for _ in range(len(y_set) * 2 - 1)]
	for (a, b, c) in vertical_lines:
		(a, b, c) = (x_encoded[a], x_encoded[b], y_encoded[c])
		for x in range(a, b + 1):
			grid[c][x] = 1
	for (d, e, f) in horizontal_lines:
		(d, e, f) = (x_encoded[d], y_encoded[e], y_encoded[f])
		for y in range(e, f + 1):
			grid[y][d] = 1
	que = deque()
	used = [[0] * len(x_set) * 2 for _ in range(len(y_set) * 2)]
	dy = [1, 1, -1, -1]
	dx = [1, -1, 1, -1]
	for k in range(4):
		(nny, nnx) = (y_encoded[0] + dy[k], x_encoded[0] + dx[k])
		if 1 <= nny < len(y_set) * 2 - 1 and 1 <= nnx < len(x_set) * 2 - 1:
			que.append((nny, nnx))
			used[nny][nnx] = 1
	ans = 0
	dy = [1, 0, -1, 0]
	dx = [0, 1, 0, -1]
	while que:
		(y, x) = que.popleft()
		if y % 2 and x % 2:
			ans += y_length[y] * x_length[x]
		for k in range(4):
			(ny, nx) = (y + dy[k], x + dx[k])
			(nny, nnx) = (ny + dy[k], nx + dx[k])
			if grid[ny][nx] == 0:
				if nny < 0 or nny >= len(y_set) * 2 - 1 or nnx < 0 or (nnx >= len(x_set) * 2 - 1):
					return 'INF'
				if not used[nny][nnx]:
					que.append((nny, nnx))
					used[nny][nnx] = 1
	return ans
print(f_single_dot())


import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
sys.setrecursionlimit(10 ** 8)
INF = float('inf')

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))

def compress(X, Y):
	dx = list(sorted(set(X)))
	dx_inv = {x: i for (i, x) in enumerate(dx)}
	dy = list(sorted(set(Y)))
	dy_inv = {y: i for (i, y) in enumerate(dy)}
	return ((dx, dy), (dx_inv, dy_inv))

def main():
	(N, M) = map(int, readline().split())
	(A, B, C) = ([0] * N, [0] * N, [0] * N)
	for i in range(N):
		(A[i], B[i], C[i]) = map(int, readline().split())
	(D, E, F) = ([0] * M, [0] * M, [0] * M)
	for i in range(M):
		(D[i], E[i], F[i]) = map(int, readline().split())
	X = [-INF, 0, INF] + A + B + D
	Y = [-INF, 0, INF] + C + E + F
	((mx, my), (invx, invy)) = compress(X, Y)
	H = len(my)
	W = len(mx)
	segx = [[0] * H for _ in range(W)]
	segy = [[0] * H for _ in range(W)]
	for (a, b, c) in zip(A, B, C):
		segx[invx[a]][invy[c] - 1] += 1
		segx[invx[b]][invy[c] - 1] -= 1
	for i in range(W - 1):
		for j in range(H):
			segx[i + 1][j] += segx[i][j]
	for (d, e, f) in zip(D, E, F):
		segy[invx[d] - 1][invy[e]] += 1
		segy[invx[d] - 1][invy[f]] -= 1
	for i in range(W):
		for j in range(H - 1):
			segy[i][j + 1] += segy[i][j]
	uf = UnionFind(W * H)
	for i in range(W):
		for j in range(H):
			if i + 1 < W and segy[i][j] == 0:
				uf.union(i + j * W, i + 1 + j * W)
			if j + 1 < H and segx[i][j] == 0:
				uf.union(i + (j + 1) * W, i + j * W)
	ushi = invx[0] + invy[0] * W
	if uf.same(ushi, 0):
		print('INF')
		return
	area = 0
	for mem in uf.members(ushi):
		(j, i) = divmod(mem, W)
		area += (mx[i + 1] - mx[i]) * (my[j + 1] - my[j])
	print(area)
	return
main()


from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import bisect
import random
from itertools import permutations, accumulate, combinations, product
import sys
import string
from bisect import bisect_left, bisect_right
from math import factorial, ceil, floor, acos, asin, atan, sqrt, tan, cos, pi
from operator import mul
from functools import reduce
from pprint import pprint
sys.setrecursionlimit(10 ** 7)
INF = 10 ** 20

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

def I():
	return int(sys.stdin.readline())

def LS():
	return sys.stdin.readline().split()

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

def IR(n):
	return [I() for i in range(n)]

def LIR(n):
	return [LI() for i in range(n)]

def SR(n):
	return [S() for i in range(n)]

def LSR(n):
	return [LS() for i in range(n)]

def SRL(n):
	return [list(S()) for i in range(n)]

def MSRL(n):
	return [[int(j) for j in list(S())] for i in range(n)]
mod = 10 ** 9 + 7
(n, m) = LI()
hor = []
ver = []
x_co = {-INF, INF}
y_co = {-INF, INF}
for _ in range(n):
	(a, b, c) = LI()
	x_co.add(a)
	x_co.add(b)
	y_co.add(c)
	ver += [(a, b, c)]
for _ in range(m):
	(d, e, f) = LI()
	x_co.add(d)
	y_co.add(e)
	y_co.add(f)
	hor += [(d, e, f)]
x_co = sorted(x_co)
y_co = sorted(y_co)
XD = {val: i for (i, val) in enumerate(x_co)}
YD = {val: i for (i, val) in enumerate(y_co)}
x_len = len(x_co) * 2 - 1
y_len = len(y_co) * 2 - 1
grid = [[0] * y_len for _ in range(x_len)]
x_range = [0] * x_len
y_range = [0] * y_len
x_range[0] = x_range[-1] = y_range[0] = y_range[-1] = INF
for (i, (x1, x2)) in enumerate(zip(x_co, x_co[1:])):
	x_range[i * 2 + 1] = x2 - x1
	if x1 <= 0 <= x2:
		sx = i * 2 + 1
for (i, (y1, y2)) in enumerate(zip(y_co, y_co[1:])):
	y_range[i * 2 + 1] = y2 - y1
	if y1 <= 0 <= y2:
		sy = i * 2 + 1
for (a, b, c) in ver:
	yi = YD[c] * 2
	for xi in range(XD[a] * 2, XD[b] * 2 + 1):
		grid[xi][yi] = 1
for (d, e, f) in hor:
	xi = XD[d] * 2
	for yi in range(YD[e] * 2, YD[f] * 2 + 1):
		grid[xi][yi] = 1
ans = x_range[sx] * y_range[sy]
grid[sx][sy] = 1
ans = 0
dq = deque([(sx, sy)])
grid[sx][sy] = 1
diff = ((0, 1), (1, 0), (-1, 0), (0, -1))
ans += x_range[sx] * y_range[sy]
while dq:
	(x, y) = dq.popleft()
	for (dx, dy) in diff:
		(nx, ny) = (dx + x, dy + y)
		if grid[nx][ny]:
			continue
		nx += dx
		ny += dy
		if grid[nx][ny]:
			continue
		grid[nx][ny] = 1
		dq.append((nx, ny))
		ans += x_range[nx] * y_range[ny]
		if ans >= INF:
			print('INF')
			exit()
print(ans)


import sys
import numpy as np

def main():
	(N, M) = list(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, INF]]))
	Y = np.unique(np.concatenate([C, [-INF, 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)

def cal_area(A, B, C, D, E, F, X, Y):
	x = np.searchsorted(X, 0, 'right') - 1
	y = np.searchsorted(Y, 0, 'right') - 1
	DX = X[1:] - X[:-1]
	DY = Y[1:] - Y[:-1]
	A = A.tolist()
	B = B.tolist()
	C = C.tolist()
	D = D.tolist()
	E = E.tolist()
	F = F.tolist()
	X = X.tolist()
	Y = Y.tolist()
	DX = DX.tolist()
	DY = DY.tolist()
	LenX = len(X)
	LenY = len(Y)
	visit = [[False] * LenY for _ in range(LenX)]
	visit[x][y] = True
	area = 0
	queue = [(x, 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
	LenX -= 1
	LenY -= 1
	q_pop = queue.pop
	q_append = queue.append
	while queue:
		(x, y) = q_pop()
		if x == 0 or x == LenX or y == 0 or (y == LenY):
			area = 0
			break
		area += DX[x] * DY[y]
		x1 = x - 1
		if not LineX[x][y] and (not visit[x1][y]):
			visit[x1][y] = True
			q_append((x1, y))
		y1 = y - 1
		if not LineY[x][y] and (not visit[x][y1]):
			visit[x][y1] = True
			q_append((x, y1))
		x1 = x + 1
		if not LineX[x1][y] and (not visit[x1][y]):
			visit[x1][y] = True
			q_append((x1, y))
		y1 = y + 1
		if not LineY[x][y1] and (not visit[x][y1]):
			visit[x][y1] = True
			q_append((x, y1))
	return area

def __starting_point():
	main()
return
__starting_point()


from collections import deque

def LI():
	return [int(i) for i in input().split()]
ans = 0
inf = 1 << 65
(n, m) = LI()
X = [0, inf, -inf]
Y = [0, inf, -inf]
V = []
H = []
for i in range(n):
	(a, b, c) = LI()
	V.append(((a, b), c))
	Y.append(c)
	X.append(a)
	X.append(b)
n += 2
V.append(((-inf, inf), inf))
V.append(((-inf, inf), -inf))
for i in range(m):
	(a, b, c) = LI()
	H.append((a, (b, c)))
	X.append(a)
	Y.append(b)
	Y.append(c)
m += 2
H.append((inf, (-inf, inf)))
H.append((-inf, (-inf, inf)))
X.sort()
xdc = {}
c = 1
for j in sorted(set(X)):
	xdc[c] = j
	c += 1
nx = c - 1
Y.sort()
ydc = {}
c = 1
for j in sorted(set(Y)):
	ydc[c] = j
	c += 1
ny = c - 1
xdcr = dict(zip(xdc.values(), xdc.keys()))
ydcr = dict(zip(ydc.values(), ydc.keys()))
mpy = [[0] * (nx + 1 + 1) for i in range(ny + 1 + 1)]
mpx = [i[:] for i in mpy]
for ((a, b), c) in V:
	mpx[ydcr[c]][xdcr[a]] += 1
	mpx[ydcr[c]][xdcr[b]] += -1
for i in range(ny + 1):
	for j in range(nx):
		mpx[i][j + 1] += mpx[i][j]
for (d, (e, f)) in H:
	mpy[ydcr[e]][xdcr[d]] += 1
	mpy[ydcr[f]][xdcr[d]] += -1
for j in range(nx + 1):
	for i in range(ny):
		mpy[i + 1][j] += mpy[i][j]
v = [[0] * (nx + 1) for i in range(ny + 1)]
q = deque([(xdcr[0], ydcr[0])])
v[ydcr[0]][xdcr[0]] = 1
while q:
	(cx, cy) = q.popleft()
	ans += (xdc[cx] - xdc[cx + 1]) * (ydc[cy] - ydc[cy + 1])
	for (dx, dy) in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
		nbx = cx + dx
		nby = cy + dy
		if not 0 <= nbx < nx or not 0 <= nby < ny or v[nby][nbx] == 1:
			continue
		if dy != 0:
			if mpx[cy + (dy + 1) // 2][cx] == 0:
				q.append((nbx, nby))
				v[nby][nbx] = 1
		elif mpy[cy][cx + (dx + 1) // 2] == 0:
			q.append((nbx, nby))
			v[nby][nbx] = 1
if ans >= inf:
	ans = 'INF'
print(ans)


import sys
from bisect import bisect_left, bisect_right

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

def input_2d_T(nrows: int, ncols: int, type=int, **kwargs):
	data = [[None] * nrows for _ in range(ncols)]
	for i in range(nrows):
		for (j, v) in enumerate(inputs(type)):
			data[j][i] = v
	return data
from collections import deque
(N, M) = inputs(int)
(A, B, C) = input_2d_T(N, 3)
(D, E, F) = input_2d_T(M, 3)
xs = sorted(set(C))
ys = sorted(set(D))
x_guard = [[False for _ in range(len(ys) + 1)] for _ in range(len(xs) + 1)]
y_guard = [[False for _ in range(len(ys) + 1)] for _ in range(len(xs) + 1)]
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 i in range(a, b):
		x_guard[c][i] = 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 i in range(e, f):
		y_guard[i][d] = True
cow = (bisect_right(xs, 0), bisect_right(ys, 0))
nexts = deque([cow])
visited = [[0 for _ in range(len(ys) + 1)] for _ in range(len(xs) + 1)]
visited[cow[0]][cow[1]] = True
area = 0
while nexts:
	(xi, yi) = nexts.popleft()
	if 0 < xi < len(xs) and 0 < yi < len(ys):
		area += (xs[xi] - xs[xi - 1]) * (ys[yi] - ys[yi - 1])
		if not visited[xi - 1][yi] and (not x_guard[xi][yi]):
			visited[xi - 1][yi] = True
			nexts.append((xi - 1, yi))
		if not visited[xi + 1][yi] and (not x_guard[xi + 1][yi]):
			visited[xi + 1][yi] = True
			nexts.append((xi + 1, yi))
		if not visited[xi][yi - 1] and (not y_guard[xi][yi]):
			visited[xi][yi - 1] = True
			nexts.append((xi, yi - 1))
		if not visited[xi][yi + 1] and (not y_guard[xi][yi + 1]):
			visited[xi][yi + 1] = True
			nexts.append((xi, yi + 1))
	else:
		area = 'INF'
		break
print(area)


from collections import deque
import bisect
INF = float('inf')
(N, M) = map(int, input().split())
xtic = {0, -INF, INF}
ytic = {0, -INF, INF}
hor = []
for _ in range(N):
	(a, b, c) = map(int, input().split())
	hor.append((c, a, b))
	xtic.add(a)
	xtic.add(b)
	ytic.add(c)
ver = []
for _ in range(M):
	(d, e, f) = map(int, input().split())
	ver.append((d, e, f))
	xtic.add(d)
	ytic.add(e)
	ytic.add(f)
xtic = list(xtic)
ytic = list(ytic)
xtic.sort()
ytic.sort()
xdic = {xtic[i]: i + 1 for i in range(len(xtic))}
ydic = {ytic[i]: i + 1 for i in range(len(ytic))}
gyaku_xdic = {xdic[k]: k for k in xdic}
gyaku_ydic = {ydic[k]: k for k in ydic}
hor.sort()
ver.sort()
hor_dic = {}
ver_dic = {}
now = None
for (c, a, b) in hor:
	(c, a, b) = (ydic[c], xdic[a], xdic[b])
	if c != now:
		hor_dic[c] = (1 << b) - (1 << a)
	else:
		hor_dic[c] |= (1 << b) - (1 << a)
	now = c
now = None
for (d, e, f) in ver:
	(d, e, f) = (xdic[d], ydic[e], ydic[f])
	if d != now:
		ver_dic[d] = (1 << f) - (1 << e)
	else:
		ver_dic[d] |= (1 << f) - (1 << e)
	now = d

def is_connected(x, y, dx, dy):
	if dx == 0:
		if dy > 0:
			if hor_wall[y + 1] >> x & 1:
				return False
			return True
		else:
			if hor_wall[y] >> x & 1:
				return False
			return True
	elif dx > 0:
		if ver_wall[x + 1] >> y & 1:
			return False
		return True
	else:
		if ver_wall[x] >> y & 1:
			return False
		return True

def calc_area(x, y):
	X = gyaku_xdic[x + 1] - gyaku_xdic[x]
	Y = gyaku_ydic[y + 1] - gyaku_ydic[y]
	return X * Y
offset = [(1, 0), (0, 1), (-1, 0), (0, -1)]
x0 = bisect.bisect(xtic, 0)
y0 = bisect.bisect(ytic, 0)
(W, H) = (len(xtic) + 1, len(ytic) + 1)
hor_wall = [0 for i in range(H)]
ver_wall = [0 for i in range(W)]
for k in hor_dic:
	hor_wall[k] = hor_dic[k]
for k in ver_dic:
	ver_wall[k] = ver_dic[k]
d = [[0 for i in range(W)] for j in range(H)]
d[y0][x0] = 1
q = deque([(x0, y0)])
area = 0
while q:
	(x, y) = q.pop()
	area += calc_area(x, y)
	for (dx, dy) in offset:
		(nx, ny) = (x + dx, y + dy)
		if 0 <= nx < W and 0 <= ny < H:
			if is_connected(x, y, dx, dy):
				if nx == 0 or ny == 0 or nx == W - 1 or (ny == H - 1):
					print('INF')
					exit()
				if d[ny][nx] == 0:
					d[ny][nx] = 1
					q.append((nx, ny))
print(area)


import sys
from collections import deque
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 18
MOD = 10 ** 9 + 7
input = lambda : sys.stdin.readline().rstrip()
YesNo = lambda b: bool([print('Yes')] if b else print('No'))
YESNO = lambda b: bool([print('YES')] if b else print('NO'))
int1 = lambda x: int(x) - 1

def main():
	(N, M) = map(int, input().split())
	(X, Y) = (set([0]), set([0]))
	(A, B, C) = ([0] * N, [0] * N, [0] * N)
	for i in range(N):
		(A[i], B[i], C[i]) = map(int, input().split())
		X.add(A[i])
		X.add(B[i])
		Y.add(C[i])
	(D, E, F) = ([0] * M, [0] * M, [0] * M)
	for i in range(M):
		(D[i], E[i], F[i]) = map(int, input().split())
		X.add(D[i])
		Y.add(E[i])
		Y.add(F[i])
	UX = list(X)
	UY = list(Y)
	UX.sort()
	UY.sort()
	(dictx, dicty) = ({n: i * 2 for (i, n) in enumerate(UX)}, {n: i * 2 for (i, n) in enumerate(UY)})
	LX = [UX[i // 2 + 1] - UX[i // 2] if i % 2 else 0 for i in range(len(UX) * 2 - 1)]
	LY = [UY[i // 2 + 1] - UY[i // 2] if i % 2 else 0 for i in range(len(UY) * 2 - 1)]
	c = [[0] * (len(UX) * 2 - 1) for _ in range(len(UY) * 2 - 1)]
	for i in range(N):
		y = dicty[C[i]]
		for x in range(dictx[A[i]], dictx[B[i]] + 1):
			c[y][x] = 1
	for i in range(M):
		x = dictx[D[i]]
		for y in range(dicty[E[i]], dicty[F[i]] + 1):
			c[y][x] = 1
	que = deque()
	used = [[0] * len(UX) * 2 for _ in range(len(UY) * 2)]
	dy = [1, 1, -1, -1]
	dx = [1, -1, 1, -1]
	for k in range(4):
		(nny, nnx) = (dicty[0] + dy[k], dictx[0] + dx[k])
		if 1 <= nny < len(UY) * 2 - 1 and 1 <= nnx < len(UX) * 2 - 1:
			que.append((nny, nnx))
			used[nny][nnx] = 1
	ans = 0
	dy = [1, 0, -1, 0]
	dx = [0, 1, 0, -1]
	while que:
		(y, x) = que.popleft()
		if y % 2 and x % 2:
			ans += LY[y] * LX[x]
		for k in range(4):
			(ny, nx) = (y + dy[k], x + dx[k])
			(nny, nnx) = (ny + dy[k], nx + dx[k])
			if c[ny][nx] == 0:
				if nny < 0 or nny >= len(UY) * 2 - 1 or nnx < 0 or (nnx >= len(UX) * 2 - 1):
					print('INF')
					exit()
				if not used[nny][nnx]:
					que.append((nny, nnx))
					used[nny][nnx] = 1
	print(ans)
main()


import bisect
import collections

class VBoarder(object):

	def __init__(self, x1, x2, y):
		self.x1 = x1
		self.x2 = x2
		self.y = y

class HBoarder(object):

	def __init__(self, x, y1, y2):
		self.x = x
		self.y1 = y1
		self.y2 = y2

class Cell(object):

	def __init__(self, x1, y1, x2, y2):
		self.x1 = x1
		self.y1 = y1
		self.x2 = x2
		self.y2 = y2
		self.up = True
		self.down = True
		self.left = True
		self.right = True
		self.checked = False

	def area(self):
		return (self.x2 - self.x1) * (self.y2 - self.y1)

	def __str__(self):
		return '(({:2d},{:2d}),({:2d},{:2d})){}{}{}{}'.format(self.x1, self.y1, self.x2, self.y2, 'Uu'[int(self.up)], 'Dd'[int(self.down)], 'Ll'[int(self.left)], 'Rr'[int(self.right)])

def main():
	(N, M) = map(int, input().split())
	vborders = [VBoarder(*map(int, input().split())) for _ in range(N)]
	hborders = [HBoarder(*map(int, input().split())) for _ in range(M)]
	y_axis = list(set([b.y for b in vborders]))
	y_axis.sort()
	y_axis = [y_axis[0] - 1] + y_axis + [y_axis[-1] + 1]
	x_axis = list(set([b.x for b in hborders]))
	x_axis.sort()
	x_axis = [x_axis[0] - 1] + x_axis + [x_axis[-1] + 1]
	cells = [[Cell(x1, y1, x2, y2) for (x1, x2) in zip(x_axis[:-1], x_axis[1:])] for (y1, y2) in zip(y_axis[:-1], y_axis[1:])]
	for b in vborders:
		y_idx = bisect.bisect_left(y_axis, b.y)
		x_idx1 = bisect.bisect_left(x_axis, b.x1)
		x_idx2 = bisect.bisect_right(x_axis, b.x2) - 1
		for x_idx in range(x_idx1, x_idx2):
			cells[y_idx - 1][x_idx].down = False
			cells[y_idx][x_idx].up = False
	for b in hborders:
		x_idx = bisect.bisect_left(x_axis, b.x)
		y_idx1 = bisect.bisect_left(y_axis, b.y1)
		y_idx2 = bisect.bisect_right(y_axis, b.y2) - 1
		for y_idx in range(y_idx1, y_idx2):
			cells[y_idx][x_idx - 1].right = False
			cells[y_idx][x_idx].left = False
	queue = collections.deque()
	area = 0
	x = bisect.bisect_right(x_axis, 0.5) - 1
	y = bisect.bisect_right(y_axis, 0.2) - 1
	queue.append((x, y))
	while len(queue) != 0:
		(x, y) = queue.popleft()
		if x == 0 or x == len(x_axis) - 1 or y == 0 or (y == len(y_axis) - 1):
			print('INF')
			return
		c = cells[y][x]
		if c.checked:
			continue
		area += c.area()
		c.checked = True
		if c.up:
			queue.append((x, y - 1))
		if c.down:
			queue.append((x, y + 1))
		if c.left:
			queue.append((x - 1, y))
		if c.right:
			queue.append((x + 1, y))
	print(area)
main()


import sys, queue, math, copy, itertools, bisect, collections, heapq

def main():
	INF = 10 ** 9 + 1
	MOD = 10 ** 9 + 7
	LI = lambda : [int(x) for x in sys.stdin.readline().split()]
	(N, M) = LI()
	x = []
	y = []
	A = []
	D = []
	for _ in range(N):
		(a, b, c) = LI()
		A.append((a, b, c))
		x.append(a)
		x.append(b)
		y.append(c)
		y.append(c)
	for _ in range(M):
		(d, e, f) = LI()
		D.append((d, e, f))
		x.append(d)
		x.append(d)
		y.append(e)
		y.append(f)
	x.append(-INF)
	x.append(INF)
	x.append(0)
	y.append(-INF)
	y.append(INF)
	y.append(0)
	x.sort()
	y.sort()
	lx = len(x)
	ly = len(y)
	fld = [[0] * ly for _ in range(lx)]
	for (a, b, c) in A:
		j = bisect.bisect_left(y, c)
		for i in range(bisect.bisect_left(x, a), bisect.bisect_left(x, b)):
			fld[i][j] = 1
	for (d, e, f) in D:
		i = bisect.bisect_left(x, d)
		for j in range(bisect.bisect_left(y, e), bisect.bisect_left(y, f)):
			fld[i][j] = 1
	q = []
	i = bisect.bisect_left(x, 0)
	j = bisect.bisect_left(y, 0)
	q.append((i, j))
	fld[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 < lx - 1 and 0 < j + dj < ly - 1:
				if fld[i + di][j + dj] == 0:
					fld[i + di][j + dj] = 1
					q.append((i + di, j + dj))
			else:
				print('INF')
				exit(0)
	print(ans)
main()


(N, M) = map(int, input().split())
ts = {}
tlis = []
for i in range(N):
	(B, C, A) = map(int, input().split())
	if A not in ts:
		tlis.append(A)
		ts[A] = []
	ts[A].append([B, C])
ys = {}
ylis = []
for i in range(M):
	(A, B, C) = map(int, input().split())
	if A not in ys:
		ylis.append(A)
		ys[A] = []
	ys[A].append([B, C])
tlis.sort()
ylis.sort()
import bisect
nowi = bisect.bisect_right(tlis, 0) - 1
nowj = bisect.bisect_right(ylis, 0) - 1
for i in ts:
	ts[i].sort()
	new = []
	lastl = None
	lastr = None
	for tmp in ts[i]:
		(nl, nr) = tmp
		if lastl == None:
			lastl = nl
			lastr = nr
		elif lastr < nl:
			new.append([lastl, lastr])
			lastl = nl
			lastr = nr
		else:
			lastr = nr
	new.append([lastl, lastr])
	ts[i] = new
for i in ys:
	ys[i].sort()
	new = []
	lastl = None
	lastr = None
	for tmp in ys[i]:
		(nl, nr) = tmp
		if lastl == None:
			lastl = nl
			lastr = nr
		elif lastr < nl:
			new.append([lastl, lastr])
			lastl = nl
			lastr = nr
		else:
			lastr = nr
	new.append([lastl, lastr])
	ys[i] = new
from collections import deque
q = deque([[nowi, nowj]])
import sys
ans = 0
end = {}
end[nowi, nowj] = 1
if len(tlis) < 2 or len(ylis) < 2:
	print('INF')
	sys.exit()
while len(q) > 0:
	(ni, nj) = q.popleft()
	if ni == -1 or nj == -1 or ni == len(tlis) - 1 or (nj == len(ylis) - 1):
		print('INF')
		sys.exit()
	up = ylis[nj]
	do = ylis[nj + 1]
	le = tlis[ni]
	ri = tlis[ni + 1]
	ans += (do - up) * (ri - le)
	flag = True
	nex = (ni, nj - 1)
	if nex not in end:
		for tmp in ys[up]:
			(L, R) = tmp
			if L <= le and ri <= R:
				flag = False
				break
		if flag:
			end[nex] = 1
			q.append([nex[0], nex[1]])
	nex = (ni, nj + 1)
	flag = True
	if nex not in end:
		for tmp in ys[do]:
			(L, R) = tmp
			if L <= le and ri <= R:
				flag = False
				break
		if flag:
			end[nex] = 1
			q.append([nex[0], nex[1]])
	nex = (ni - 1, nj)
	flag = True
	if nex not in end:
		for tmp in ts[le]:
			(L, R) = tmp
			if L <= up and do <= R:
				flag = False
				break
		if flag:
			end[nex] = 1
			q.append([nex[0], nex[1]])
	nex = (ni + 1, nj)
	flag = True
	if nex not in end:
		for tmp in ts[ri]:
			(L, R) = tmp
			if L <= up and do <= R:
				flag = False
				break
		if flag:
			end[nex] = 1
			q.append([nex[0], nex[1]])
print(ans)


from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import math
import bisect
import random
from itertools import permutations, accumulate, combinations, product
import sys
import string
from bisect import bisect_left, bisect_right
from math import factorial, ceil, floor, gcd
from operator import mul
from functools import reduce
from operator import mul
from pprint import pprint
sys.setrecursionlimit(2147483647)
INF = 10 ** 20

def LI():
	return list(map(int, sys.stdin.buffer.readline().split()))

def I():
	return int(sys.stdin.buffer.readline())

def LS():
	return sys.stdin.buffer.readline().rstrip().decode('utf-8').split()

def S():
	return sys.stdin.buffer.readline().rstrip().decode('utf-8')

def IR(n):
	return [I() for i in range(n)]

def LIR(n):
	return [LI() for i in range(n)]

def SR(n):
	return [S() for i in range(n)]

def LSR(n):
	return [LS() for i in range(n)]

def SRL(n):
	return [list(S()) for i in range(n)]

def MSRL(n):
	return [[int(j) for j in list(S())] for i in range(n)]
mod = 1000000007
(n, m) = LI()
horizontal = []
vertical = []
x_co = {INF, -INF}
y_co = {INF, -INF}
for _ in range(n):
	(a, b, c) = LI()
	x_co.add(a)
	x_co.add(b)
	y_co.add(c)
	vertical += [(a, b, c)]
for _ in range(m):
	(d, e, f) = LI()
	x_co.add(d)
	y_co.add(e)
	y_co.add(f)
	horizontal += [(d, e, f)]
x_len = len(x_co) * 2 - 1
y_len = len(y_co) * 2 - 1
x_co = sorted(list(x_co))
y_co = sorted(list(y_co))
x_comp = {val: i for (i, val) in enumerate(x_co)}
y_comp = {val: i for (i, val) in enumerate(y_co)}
grid = [[0] * y_len for _ in range(x_len)]
x_range = [0] * x_len
y_range = [0] * y_len
x_range[0] = x_range[-1] = INF
y_range[0] = y_range[-1] = INF
for (i, (x1, x2)) in enumerate(zip(x_co, x_co[1:])):
	x_range[i * 2 + 1] = x2 - x1
	if x1 <= 0 <= x2:
		sx = i * 2 + 1
for (i, (y1, y2)) in enumerate(zip(y_co, y_co[1:])):
	y_range[i * 2 + 1] = y2 - y1
	if y1 <= 0 <= y2:
		sy = i * 2 + 1
for (a, b, c) in vertical:
	y = y_comp[c] * 2
	for x in range(x_comp[a] * 2 + 1, x_comp[b] * 2 + 1, 2):
		grid[x][y] = 1
for (d, e, f) in horizontal:
	x = x_comp[d] * 2
	for y in range(y_comp[e] * 2 + 1, y_comp[f] * 2 + 1, 2):
		grid[x][y] = 1
ans = 0
dq = deque([(sx, sy)])
grid[sx][sy] = 1
diff = ((0, 1), (1, 0), (-1, 0), (0, -1))
ans += x_range[sx] * y_range[sy]
while dq:
	(x, y) = dq.popleft()
	for (dx, dy) in diff:
		(nx, ny) = (dx + x, dy + y)
		if grid[nx][ny]:
			continue
		nx += dx
		ny += dy
		if grid[nx][ny]:
			continue
		grid[nx][ny] = 1
		dq.append((nx, ny))
		ans += x_range[nx] * y_range[ny]
		if ans >= INF:
			print('INF')
			exit()
print(ans)


import sys
input = sys.stdin.readline

def compress(set_):
	array2 = sorted(list(set_))
	memo = {value: index for (index, value) in enumerate(array2)}
	return memo

def calc_s(hi, wj):
	res = abs(h_rests[hi] - h_rests[hi - 1]) * abs(w_rests[wj] - w_rests[wj + 1])
	return res
(h, w) = map(int, input().split())
info_h = [list(map(int, input().split())) for i in range(h)]
info_w = [list(map(int, input().split())) for i in range(w)]
INF = 10 ** 20
h_coords = set([-INF, 0, INF])
w_coords = set([-INF, 0, INF])
for (h1, h2, w1) in info_h:
	h_coords.add(h1)
	h_coords.add(h2)
	w_coords.add(w1)
for (h1, w1, w2) in info_w:
	h_coords.add(h1)
	w_coords.add(w1)
	w_coords.add(w2)
h_comps = compress(h_coords)
w_comps = compress(w_coords)
h_rests = {h_comps[index]: index for index in h_comps}
w_rests = {w_comps[index]: index for index in w_comps}
grid = [[1] * (len(w_rests) + 2) for i in range(len(h_rests) + 2)]
for (h1, h2, w1) in info_h:
	(h1, h2, w1) = (h_comps[h1], h_comps[h2], w_comps[w1])
	for hi in range(h1 + 1, h2 + 1):
		grid[hi][w1] *= 2
for (h1, w1, w2) in info_w:
	(h1, w1, w2) = (h_comps[h1], w_comps[w1], w_comps[w2])
	for wi in range(w1, w2):
		grid[h1][wi] *= 3
used = [[False] * (len(w_rests) + 2) for i in range(len(h_rests) + 2)]
(si, sw) = (h_comps[0], w_comps[0])
OFFSET = 5000
stack = [si * 5000 + sw]
ans = 0
used[si][sw] = True
while stack:
	ij = stack.pop()
	(i, j) = divmod(ij, OFFSET)
	ans += calc_s(i, j)
	(nxt_i, nxt_j) = (i - 1, j)
	if grid[nxt_i][nxt_j] % 3 == 0 or used[nxt_i][nxt_j]:
		pass
	else:
		used[nxt_i][nxt_j] = True
		stack.append(nxt_i * OFFSET + nxt_j)
	(nxt_i, nxt_j) = (i + 1, j)
	if grid[i][j] % 3 == 0 or used[nxt_i][nxt_j]:
		pass
	else:
		used[nxt_i][nxt_j] = True
		stack.append(nxt_i * OFFSET + nxt_j)
	(nxt_i, nxt_j) = (i, j + 1)
	if grid[nxt_i][nxt_j] % 2 == 0 or used[nxt_i][nxt_j]:
		pass
	else:
		used[nxt_i][nxt_j] = True
		stack.append(nxt_i * OFFSET + nxt_j)
	(nxt_i, nxt_j) = (i, j - 1)
	if grid[i][j] % 2 == 0 or used[nxt_i][nxt_j]:
		pass
	else:
		used[nxt_i][nxt_j] = True
		stack.append(nxt_i * OFFSET + nxt_j)
	if ans > INF:
		print('INF')
		exit()
print(ans)


from collections import deque

def main():
	(n, m) = map(int, input().split())
	INF = 10 ** 20
	mapX = {INF, -INF}
	mapY = {INF, -INF}
	dx = [-1, 0, 1, 0]
	dy = [0, -1, 0, 1]
	lh = [None] * n
	lv = [None] * m
	for i in range(n):
		(a, b, c) = map(int, input().split())
		mapX.add(a)
		mapX.add(b)
		mapY.add(c)
		lh[i] = [a, b, c]
	for i in range(m):
		(d, e, f) = map(int, input().split())
		mapX.add(d)
		mapY.add(e)
		mapY.add(f)
		lv[i] = [d, e, f]
	x_len = len(mapX) * 2 - 1
	y_len = len(mapY) * 2 - 1
	(mapX, mapY) = (sorted(list(mapX)), sorted(list(mapY)))
	(mapXi, mapYi) = ({val: i for (i, val) in enumerate(mapX)}, {val: i for (i, val) in enumerate(mapY)})
	grid = [[0] * y_len for _ in range(x_len)]
	x_range = [0] * x_len
	y_range = [0] * y_len
	x_range[0] = x_range[-1] = INF
	y_range[0] = y_range[-1] = INF
	for (i, (x1, x2)) in enumerate(zip(mapX, mapX[1:])):
		x_range[i * 2 + 1] = x2 - x1
		if x1 <= 0 <= x2:
			sx = i * 2 + 1
	for (i, (y1, y2)) in enumerate(zip(mapY, mapY[1:])):
		y_range[i * 2 + 1] = y2 - y1
		if y1 <= 0 <= y2:
			sy = i * 2 + 1
	for (a, b, c) in lh:
		y = mapYi[c] * 2
		for x in range(mapXi[a] * 2 + 1, mapXi[b] * 2 + 1, 2):
			grid[x][y] = 1
	for (a, b, c) in lv:
		x = mapXi[a] * 2
		for y in range(mapYi[b] * 2 + 1, mapYi[c] * 2 + 1, 2):
			grid[x][y] = 1
	q = deque()
	grid[sx][sy] = 1
	q.appendleft([sx, sy])
	ans = x_range[sx] * y_range[sy]
	while q:
		(x, y) = q.pop()
		for i in range(4):
			(nx, ny) = (x + dx[i], y + dy[i])
			if grid[nx][ny]:
				continue
			nx += dx[i]
			ny += dy[i]
			if grid[nx][ny]:
				continue
			grid[nx][ny] = 1
			q.appendleft([nx, ny])
			ans += x_range[nx] * y_range[ny]
			if ans >= INF:
				print('INF')
				return
	print(ans)
main()


import sys
import operator
from itertools import repeat
from functools import partial, reduce
from typing import Any, Callable, Iterable, Tuple, Union
Indices = Union[int, slice, Tuple[Union[int, slice]]]
ndgetter = (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]])
ndinitializor = (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])])
ndshapegetter = (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])))
nditerator = (lambda s: 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])))

class nd(object):
	__slots__ = ['_data', 'shape', '_getter_getter', '_setter_getter', '_iterator', '_initializer']

	def __init__(self, data: list, shape: Tuple[int]):
		self._data = data
		self.shape = shape
		self._getter_getter = ndgetter[len(self.shape)]
		self._setter_getter = ndgetter[len(self.shape) - 1]
		self._iterator = nditerator[len(self.shape)]
		self._initializer = ndinitializor[len(self.shape)]

	def __len__(self):
		return len(self._data)

	def __getitem__(self, key):
		return self._data[key]

	def __setitem__(self, key, value):
		self._data[key] = value

	def __iter__(self):
		cls = type(self)
		sub_shape = self.shape[1:]
		if 0 < len(sub_shape):
			return (cls(v, sub_shape) for v in self._data)
		else:
			return iter(self._data)

	def at(self, indices: Tuple[int]):
		return self._getter_getter(self._data, indices)

	def set_at(self, indices: Tuple[int], value):
		self._setter_getter(self._data, indices[:-1])[indices[-1]] = value

	def fill(self, value):
		for indices in self._iterator(self.shape):
			self._setter_getter(self._data, indices[:-1])[indices[-1]] = value

	def apply_indices_inplace(self, func: Callable[[Any, Tuple[int]], Any]):
		for indices in self._iterator(self.shape):
			a = self._setter_getter(self._data, indices[:-1])
			a[indices[-1]] = func(a[indices[-1]], indices)

	def apply_inplace(self, func: Callable[[Any], Any]):
		for indices in self._iterator(self.shape):
			a = self._setter_getter(self._data, indices[:-1])
			a[indices[-1]] = func(a[indices[-1]])

	def apply_indices(self, func: Callable[[Any, Tuple[int]], Any]):
		new_data = self._initializer(self.shape, None)
		for indices in self._iterator(self.shape):
			a = self._setter_getter(new_data, indices[:-1])
			a[indices[-1]] = func(a[indices[-1]], indices)
		return nd(new_data, self.shape)

	def apply(self, func: Callable[[Any], Any]):
		new_data = self._initializer(self.shape, None)
		for indices in self._iterator(self.shape):
			a = self._setter_getter(new_data, indices[:-1])
			a[indices[-1]] = func(a[indices[-1]])
		return nd(new_data, self.shape)

	def operate(self, other, operator):
		if not isinstance(other, list):
			return self.apply(lambda element: operator(element, other))
		else:
			return self.apply_indices(lambda element, indices: operator(element, self._getter_getter(other, indices)))

	def roperate(self, other, operator):
		if not isinstance(other, list):
			return self.apply(lambda element: operator(other, element))
		else:
			return self.apply_indices(lambda element, indices: operator(self._getter_getter(other, indices), element))

	def ioperate(self, other, operator):
		if not isinstance(other, list):
			self.apply_inplace(lambda element: operator(element, other))
		else:
			self.apply_indices_inplace(lambda element, indices: operator(element, self._getter_getter(other, indices)))
		return self

	def rioperate(self, other, operator):
		if not isinstance(other, list):
			return self.apply_inplace(lambda element: operator(other, element))
		else:
			return self.apply_indices_inplace(lambda element, indices: operator(self._getter_getter(other, indices), element))
		return self

	def __add__(self, other):
		return self.operate(other, operator.add)

	def __radd__(self, other):
		return self.roperate(other, operator.add)

	def __iadd__(self, other):
		return self.ioperate(other, operator.add)

	def __sub__(self, other):
		return self.operate(other, operator.sub)

	def __rsub__(self, other):
		return self.roperate(other, operator.sub)

	def __isub__(self, other):
		return self.ioperate(other, operator.sub)

	def __mul__(self, other):
		return self.operate(other, operator.mul)

	def __rmul__(self, other):
		return self.roperate(other, operator.mul)

	def __imul__(self, other):
		return self.ioperate(other, operator.mul)

	def __matmul__(self, other):
		return self.operate(other, operator.matmul)

	def __rmatmul__(self, other):
		return self.roperate(other, operator.matmul)

	def __imatmul__(self, other):
		return self.ioperate(other, operator.matmul)

	def __truediv__(self, other):
		return self.operate(other, operator.truediv)

	def __rtruediv__(self, other):
		return self.roperate(other, operator.truediv)

	def __itruediv__(self, other):
		return self.ioperate(other, operator.truediv)

	def __floordiv__(self, other):
		return self.operate(other, operator.floordiv)

	def __rfloordiv__(self, other):
		return self.roperate(other, operator.floordiv)

	def __ifloordiv__(self, other):
		return self.ioperate(other, operator.floordiv)

	def __mod__(self, other):
		return self.operate(other, operator.mod)

	def __rmod__(self, other):
		return self.roperate(other, operator.mod)

	def __imod__(self, other):
		return self.ioperate(other, operator.mod)

	def __divmod__(self, other):
		return self.operate(other, operator.divmod)

	def __rdivmod__(self, other):
		return self.roperate(other, operator.divmod)

	def __idivmod__(self, other):
		return self.ioperate(other, operator.divmod)

	def __pow__(self, other):
		return self.operate(other, operator.pow)

	def __rpow__(self, other):
		return self.roperate(other, operator.pow)

	def __ipow__(self, other):
		return self.ioperate(other, operator.pow)

	def __lshift__(self, other):
		return self.operate(other, operator.lshift)

	def __rlshift__(self, other):
		return self.roperate(other, operator.lshift)

	def __ilshift__(self, other):
		return self.ioperate(other, operator.lshift)

	def __rshift__(self, other):
		return self.operate(other, operator.rshift)

	def __rrshift__(self, other):
		return self.roperate(other, operator.rshift)

	def __irshift__(self, other):
		return self.ioperate(other, operator.rshift)

	def __and__(self, other):
		return self.operate(other, operator.and_)

	def __rand__(self, other):
		return self.roperate(other, operator.and_)

	def __iand__(self, other):
		return self.ioperate(other, operator.and_)

	def __xor__(self, other):
		return self.operate(other, operator.xor)

	def __rxor__(self, other):
		return self.roperate(other, operator.xor)

	def __ixor__(self, other):
		return self.ioperate(other, operator.xor)

	def __or__(self, other):
		return self.operate(other, operator.or_)

	def __ror__(self, other):
		return self.roperate(other, operator.or_)

	def __ior__(self, other):
		return self.ioperate(other, operator.or_)

	def __neg__(self, other):
		return self.apply(other, operator.neg)

	def __pos__(self, other):
		return self.apply(other, operator.pos)

	def __abs__(self, other):
		return self.apply(other, operator.abs)

	def __invert__(self, other):
		return self.apply(other, operator.invert)

	def __lt__(self, other):
		return self.operate(other, operator.lt)

	def __le__(self, other):
		return self.operate(other, operator.le)

	def __eq__(self, other):
		return self.operate(other, operator.eq)

	def __ne__(self, other):
		return self.operate(other, operator.ne)

	def __gt__(self, other):
		return self.operate(other, operator.gt)

	def __ge__(self, other):
		return self.operate(other, operator.ge)

	@classmethod
	def full(cls, fill_value, shape: Union[int, Tuple[int], Iterable[int]]):
		if isinstance(shape, int):
			return cls(ndinitializor[0](shape, fill_value), (shape,))
		elif not isinstance(shape, tuple):
			shape = tuple(shape)
		return cls(ndinitializor[len(shape)](shape, fill_value), shape)

	@classmethod
	def list_fromiter(cls, iterable, ndim=1):
		if ndim == 1:
			return list(iterable)
		else:
			return list(map(cls.list_fromiter, iterable))

	@classmethod
	def fromiter(cls, iterable, ndim=1):
		new_data = cls.list_fromiter(iterable, ndim)
		return cls(new_data, ndshapegetter[ndim](new_data))

	@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)

	@classmethod
	def partial_map(cls, func, *left_args, **left_kwargs):

		def nd_func(a: nd, *right_args, **right_kwargs):
			return cls.fromiter((func(*left_args, v, *right_args, **left_kwargs, **right_kwargs) for v in a._data))
		return nd_func

	@classmethod
	def vectorize(cls, func, *left_args, **left_kwargs):

		def nd_func(a: nd, *right_args, **right_kwargs):
			return a.apply(lambda v: func(*left_args, v, *right_args, **left_kwargs, **right_kwargs))
		return nd_func

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
import operator
from typing import Optional

class BreadthFirstSearch(object):

	def __init__(self, shape: Tuple[int]):
		self.shape = shape
		self.pushed = nd.zeros(shape, type=bool)
		self._deque = deque()

	def push(self, position: Tuple[int]):
		if not self.pushed.at(position):
			self.pushed.set_at(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)
C = nd.partial_map(bisect_right, xs)(C)
A = nd.partial_map(bisect_left, ys)(A)
A += 1
B = nd.partial_map(bisect_right, ys)(B)
D = nd.partial_map(bisect_right, ys)(D)
E = nd.partial_map(bisect_left, xs)(E)
E += 1
F = nd.partial_map(bisect_right, xs)(F)
for (a, b, c) in zip(A, B, C):
	for y in range(a, b):
		x_guard[c][y] = True
for (d, e, f) in zip(D, E, 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)


import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
sys.setrecursionlimit(10 ** 8)
INF = float('inf')

class UnionFind(object):

	def __init__(self, N):
		self.tree = [-1] * N

	def root(self, i):
		if self.tree[i] < 0:
			return i
		else:
			self.tree[i] = self.root(self.tree[i])
			return self.tree[i]

	def same(self, x, y):
		return self.root(x) == self.root(y)

	def unite(self, x, y):
		x = self.root(x)
		y = self.root(y)
		if x != y:
			if self.tree[y] < self.tree[x]:
				(x, y) = (y, x)
			self.tree[x] += self.tree[y]
			self.tree[y] = x
		return x == y

def main():
	(N, M) = map(int, readline().split())
	(x_coord, y_coord) = ({-INF, 0, INF}, {-INF, 0, INF})
	(A, B, C) = ([0] * N, [0] * N, [0] * N)
	for i in range(N):
		(a, b, c) = map(int, readline().split())
		(A[i], B[i], C[i]) = (a, b, c)
		x_coord.add(a)
		x_coord.add(b)
		y_coord.add(c)
	(D, E, F) = ([0] * M, [0] * M, [0] * M)
	for i in range(M):
		(d, e, f) = map(int, readline().split())
		(D[i], E[i], F[i]) = (d, e, f)
		x_coord.add(d)
		y_coord.add(e)
		y_coord.add(f)
	mx = list(sorted(x_coord))
	my = list(sorted(y_coord))
	(invx, invy) = ({}, {})
	for (i, x) in enumerate(mx):
		invx[x] = i
	for (i, y) in enumerate(my):
		invy[y] = i
	H = len(my)
	W = len(mx)
	segx = [[0] * H for _ in range(W)]
	segy = [[0] * H for _ in range(W)]
	for (a, b, c) in zip(A, B, C):
		segx[invx[a]][invy[c] - 1] += 1
		segx[invx[b]][invy[c] - 1] -= 1
	for i in range(W - 1):
		for j in range(H):
			segx[i + 1][j] += segx[i][j]
	for (d, e, f) in zip(D, E, F):
		segy[invx[d] - 1][invy[e]] += 1
		segy[invx[d] - 1][invy[f]] -= 1
	for i in range(W):
		for j in range(H - 1):
			segy[i][j + 1] += segy[i][j]
	uf = UnionFind(W * H)
	for i in range(W):
		for j in range(H):
			if i + 1 < W and segy[i][j] == 0:
				uf.unite(i + j * W, i + 1 + j * W)
			if j + 1 < H and segx[i][j] == 0:
				uf.unite(i + (j + 1) * W, i + j * W)
	ushi = invx[0] + invy[0] * W
	if uf.same(ushi, 0):
		print('INF')
		return
	area = 0
	for i in range(W - 1):
		for j in range(H - 1):
			if uf.same(ushi, i + j * W):
				area += (mx[i + 1] - mx[i]) * (my[j + 1] - my[j])
	print(area)
	return
main()


import sys
from collections import deque
readline = sys.stdin.readline
readall = sys.stdin.read
ns = lambda : readline().rstrip()
ni = lambda : int(readline().rstrip())
nm = lambda : map(int, readline().split())
nl = lambda : list(map(int, readline().split()))
prn = lambda x: print(*x, sep='\n')

def solve():
	(n, m) = nm()
	ver = [tuple(nm()) for _ in range(n)]
	hor = [tuple(nm()) for _ in range(m)]
	xli = [0] * (2 * n + m + 1)
	yli = [0] * (n + 2 * m + 1)
	for (i, (a, b, c)) in enumerate(ver):
		xli[i * 2] = a
		xli[i * 2 + 1] = b
		yli[i] = c
	for (i, (a, b, c)) in enumerate(hor):
		xli[2 * n + i] = a
		yli[n + 2 * i] = b
		yli[n + 2 * i + 1] = c
	xli = sorted(set(xli))
	yli = sorted(set(yli))
	xdic = {x: i for (i, x) in enumerate(xli)}
	ydic = {x: i for (i, x) in enumerate(yli)}
	H = len(yli) * 2 + 1
	W = len(xli) * 2 + 1
	G = [[0] * W for _ in range(H)]
	for (a, b, c) in ver:
		a = xdic[a]
		b = xdic[b]
		c = ydic[c]
		if a > b:
			(a, b) = (b, a)
		for i in range(2 * a + 1, 2 * b + 2):
			G[2 * c + 1][i] = 1
	for (a, b, c) in hor:
		a = xdic[a]
		b = ydic[b]
		c = ydic[c]
		if b > c:
			(b, c) = (c, b)
		for i in range(2 * b + 1, 2 * c + 2):
			G[i][2 * a + 1] = 1
	q = deque()
	sx = xdic[0] * 2 + 1
	sy = ydic[0] * 2 + 1
	G[sy - 1][sx - 1] = 2
	q.append((sy - 1, sx - 1))
	ans = 0
	while q:
		(y, x) = q.popleft()
		for (ny, nx) in ((y + 2, x), (y - 2, x), (y, x + 2), (y, x - 2)):
			if 0 <= ny < H and 0 <= nx < W and (G[ny][nx] == 0) and (G[(ny + y) // 2][(nx + x) // 2] != 1):
				G[ny][nx] = 2
				q.append((ny, nx))
	for ny in range(H):
		for nx in range(W):
			if G[ny][nx] > 1:
				if ny == 0 or ny == H - 1 or nx == 0 or (nx == W - 1):
					print('INF')
					return
				if ny % 2 == nx % 2 == 0:
					ans += (yli[ny // 2] - yli[ny // 2 - 1]) * (xli[nx // 2] - xli[nx // 2 - 1])
	print(ans)
	return
solve()


I = lambda : map(int, input().split())
F = 1e+21
r = range
(n, m) = I()
f = [-F, F]
X = set([0] + f)
Y = set(X)
R = [(f, F), (f, -F)]
H = [(F, f), (-F, f)]
for i in r(n):
	(a, b, c) = I()
	R += [((a, b), c)]
	Y.add(c)
	X.add(a)
	X.add(b)
for i in r(m):
	(a, b, c) = I()
	H += [(a, (b, c))]
	X.add(a)
	Y.add(b)
	Y.add(c)
s = dict(enumerate(sorted(X)))
K = len(s)
t = dict(enumerate(sorted(Y)))
L = len(t)
h = dict(zip(s.values(), s.keys()))
w = dict(zip(t.values(), t.keys()))
V = [[0] * -~K for i in r(L + 1)]
U = [i[:] for i in V]
v = [i[:] for i in V]
for ((a, b), c) in R:
	U[w[c]][h[a]] += 1
	U[w[c]][h[b]] += -1
for i in r(L + 1):
	for j in r(K):
		U[i][j + 1] += U[i][j]
for (d, (e, f)) in H:
	V[w[e]][h[d]] += 1
	V[w[f]][h[d]] += -1
for j in r(K + 1):
	for i in r(L):
		V[i + 1][j] += V[i][j]
q = [(h[0], w[0])]
v[w[0]][h[0]] = 1
a = 0
while q:
	(x, y) = q.pop()
	a += (s[x] - s[x + 1]) * (t[y] - t[y + 1])
	for (e, f) in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
		c = x + e
		d = y + f
		if (0 <= c < K) * (0 <= d < L) * v[d][c] == 0:
			if U[-~f // 2 + y][x] == e == 0 or V[y][-~e // 2 + x] == 0 == f:
				q += [(c, d)]
				v[d][c] = 1
if a > F:
	a = 'INF'
print(a)


import sys
INF = 1 << 60
MOD = 10 ** 9 + 7
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)
	(m, n) = (len(X), len(Y))
	cX = {v: i for (i, v) in enumerate(X)}
	cY = {v: i for (i, v) in enumerate(Y)}
	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
	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])
		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))
		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))
		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))
		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()


import sys
readline = sys.stdin.readline

def compress(L):
	L2 = list(set(L))
	L2.sort()
	C = {v: k for (k, v) in enumerate(L2)}
	return (L2, C)
(N, M) = map(int, readline().split())
INF = 10 ** 9 + 7
Wp = [tuple(map(int, readline().split())) for _ in range(N)]
Hp = [tuple(map(int, readline().split())) for _ in range(M)]
epx = [0, INF, -INF]
epy = [0, INF, -INF]
for (X, st, en) in Hp:
	epx.append(X)
	epy.append(st)
	epy.append(en)
for (st, en, Y) in Wp:
	epy.append(Y)
	epx.append(st)
	epx.append(en)
(Elx, Cex) = compress(epx)
(Ely, Cey) = compress(epy)
Lx = len(Elx)
Ly = len(Ely)
UD = [[0] * (Lx + 1) for _ in range(Ly + 1)]
LR = [[0] * (Lx + 1) for _ in range(Ly + 1)]
for (X, st, en) in Hp:
	LR[Cey[st]][Cex[X]] += 1
	LR[Cey[en]][Cex[X]] -= 1
for (st, en, Y) in Wp:
	UD[Cey[Y]][Cex[st]] += 1
	UD[Cey[Y]][Cex[en]] -= 1
for x in range(1, Lx):
	for y in range(Ly):
		UD[y][x] += UD[y][x - 1]
for y in range(1, Ly):
	for x in range(Lx):
		LR[y][x] += LR[y - 1][x]
ed = set()
for i in range(Lx):
	ed.add((i, 0))
	ed.add((i, Ly - 1))
for j in range(Ly):
	ed.add((0, j))
	ed.add((Lx - 1, j))
geta = Ly
st = Cex[0] * geta + Cey[0]
stack = [st]
used = [False] * (Lx * Ly)
used[st] = True
ans = 'INF'
area = 0
while stack:
	(vx, vy) = divmod(stack.pop(), geta)
	if (vx, vy) in ed:
		break
	area += (Elx[vx + 1] - Elx[vx]) * (Ely[vy + 1] - Ely[vy])
	if not UD[vy + 1][vx] and (not used[vx * geta + vy + 1]):
		used[vx * geta + vy + 1] = True
		stack.append(vx * geta + vy + 1)
	if not UD[vy][vx] and (not used[vx * geta + vy - 1]):
		used[vx * geta + vy - 1] = True
		stack.append(vx * geta + vy - 1)
	if not LR[vy][vx + 1] and (not used[(vx + 1) * geta + vy]):
		used[(vx + 1) * geta + vy] = True
		stack.append((vx + 1) * geta + vy)
	if not LR[vy][vx] and (not used[(vx - 1) * geta + vy]):
		used[(vx - 1) * geta + vy] = True
		stack.append((vx - 1) * geta + vy)
else:
	ans = area
print(ans)


import sys
(N, M) = map(int, input().split())
X = []
for _ in range(N):
	(a, b, c) = map(int, input().split())
	X.append((a, b, c))
Y = []
for _ in range(M):
	(a, b, c) = map(int, input().split())
	Y.append((b, c, a))
X.sort(key=lambda x: x[2])
Y.sort(key=lambda x: x[2])
dxs = []
bc = X[0][2]
for (_, _, c) in X[1:]:
	dxs.append(c - bc)
	bc = c
dys = []
bc = Y[0][2]
for (_, _, c) in Y[1:]:
	dys.append(c - bc)
	bc = c
Ws = set()
for (i, (a, b, _)) in enumerate(X):
	yi = 0
	for ((_, _, z1), (_, _, z2)) in zip(Y, Y[1:]):
		if z1 == z2 or (a <= z1 and z2 <= b):
			Ws.add(((i - 1, yi), (i, yi)))
			Ws.add(((i, yi), (i - 1, yi)))
		yi += 1
for (i, (a, b, _)) in enumerate(Y):
	yi = 0
	for ((_, _, z1), (_, _, z2)) in zip(X, X[1:]):
		if z1 == z2 or (a <= z1 and z2 <= b):
			Ws.add(((yi, i - 1), (yi, i)))
			Ws.add(((yi, i), (yi, i - 1)))
		yi += 1
fci = -1
for (_, _, c) in X:
	if 0 < c:
		break
	fci += 1
if fci < 0 or N - 1 <= fci:
	print('INF')
	sys.exit()
fcj = -1
for (_, _, c) in Y:
	if 0 < c:
		break
	fcj += 1
if fcj < 0 or M - 1 <= fcj:
	print('INF')
	sys.exit()
stack = [(fci, fcj)]
S = 0
vs = set([(fci, fcj)])
while stack:
	(i, j) = stack.pop()
	S += dxs[i] * dys[j]
	for (k, l) in [(i + 1, j), (i - 1, j), (i, j - 1), (i, j + 1)]:
		if ((i, j), (k, l)) in Ws:
			continue
		if k < 0 or N - 2 < k:
			print('INF')
			sys.exit()
		if l < 0 or M - 2 < l:
			print('INF')
			sys.exit()
		if (k, l) in vs:
			continue
		vs.add((k, l))
		stack.append((k, l))
print(S)


I = lambda : [int(i) for i in input().split()]
F = 1 << 65
(n, m) = I()
X = set([0, F, -F])
Y = set(X)
R = []
H = []
for i in range(n):
	(a, b, c) = I()
	R.append(((a, b), c))
	Y.add(c)
	X.add(a)
	X.add(b)
n += 2
R += [((-F, F), F), ((-F, F), -F)]
for i in range(m):
	(a, b, c) = I()
	H.append((a, (b, c)))
	X.add(a)
	Y.add(b)
	Y.add(c)
m += 2
H += [(F, (-F, F)), (-F, (-F, F))]
xdc = {}
c = 1
for j in sorted(X):
	xdc[c] = j
	c += 1
nx = c - 1
ydc = {}
c = 1
for j in sorted(Y):
	ydc[c] = j
	c += 1
ny = c - 1
xdcr = dict(zip(xdc.values(), xdc.keys()))
ydcr = dict(zip(ydc.values(), ydc.keys()))
V = [[0] * (nx + 1 + 1) for i in range(ny + 1 + 1)]
U = [i[:] for i in V]
for ((a, b), c) in R:
	U[ydcr[c]][xdcr[a]] += 1
	U[ydcr[c]][xdcr[b]] += -1
for i in range(ny + 1):
	for j in range(nx):
		U[i][j + 1] += U[i][j]
for (d, (e, f)) in H:
	V[ydcr[e]][xdcr[d]] += 1
	V[ydcr[f]][xdcr[d]] += -1
for j in range(nx + 1):
	for i in range(ny):
		V[i + 1][j] += V[i][j]
v = [[0] * (nx + 1) for i in range(ny + 1)]
q = [(xdcr[0], ydcr[0])]
v[ydcr[0]][xdcr[0]] = 1
a = 0
while q:
	(cx, cy) = q.pop()
	a += (xdc[cx] - xdc[cx + 1]) * (ydc[cy] - ydc[cy + 1])
	for (dx, dy) in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
		nbx = cx + dx
		nby = cy + dy
		if 0 > nbx >= nx or 0 > nby >= ny or v[nby][nbx] == 1:
			continue
		if dy != 0:
			if U[-~dy // 2 + cy][cx] == 0:
				q.append((nbx, nby))
				v[nby][nbx] = 1
		elif V[cy][-~dx // 2 + cx] == 0:
			q.append((nbx, nby))
			v[nby][nbx] = 1
if a >= F:
	a = 'INF'
print(a)


import sys
input = sys.stdin.readline
from collections import deque
from bisect import bisect_left

def main():
	(n, m) = map(int, input().split())
	(X, Y) = (set(), set())
	H = []
	V = []
	for _ in range(n):
		(a, b, c) = map(int, input().split())
		X.add(a)
		X.add(b)
		Y.add(c)
		V.append((a, b, c))
	for _ in range(m):
		(d, e, f) = map(int, input().split())
		X.add(d)
		Y.add(e)
		Y.add(f)
		H.append((d, e, f))
	X = list(X)
	Y = list(Y)
	X.sort()
	Y.sort()
	MapX = {}
	MapY = {}
	for (i, x) in enumerate(X):
		MapX[x] = i
	for (i, y) in enumerate(Y):
		MapY[y] = i
	h = len(MapX) * 2
	w = len(MapY) * 2
	Grid = [[0] * w for _ in range(h)]
	for (a, b, c) in V:
		a = MapX[a] * 2
		b = MapX[b] * 2
		c = MapY[c] * 2
		for x in range(a, b + 1):
			Grid[x][c] = 1
	for (d, e, f) in H:
		d = MapX[d] * 2
		e = MapY[e] * 2
		f = MapY[f] * 2
		for y in range(e, f + 1):
			Grid[d][y] = 1
	s_x = bisect_left(X, 0) * 2 - 1
	s_y = bisect_left(Y, 0) * 2 - 1
	if s_x < 0 or s_y < 0 or s_x >= h - 1 or (s_y >= w - 1):
		return 'INF'
	Grid[s_x][s_y] = 1
	D = [(1, 0), (-1, 0), (0, 1), (0, -1)]
	ans = 0
	q = deque([(s_x, s_y)])
	Grid[s_x][s_y] = 1
	while q:
		(x, y) = q.popleft()
		ans += (X[x // 2 + 1] - X[x // 2]) * (Y[y // 2 + 1] - Y[y // 2])
		for (dx, dy) in D:
			(half_x, half_y) = (x + dx, y + dy)
			if Grid[half_x][half_y] != 0:
				continue
			(to_x, to_y) = (half_x + dx, half_y + dy)
			if to_x < 0 or to_y < 0 or to_x == h - 1 or (to_y == w - 1):
				return 'INF'
			if Grid[to_x][to_y] != 0:
				continue
			Grid[to_x][to_y] = 1
			q.append((to_x, to_y))
	return ans
print(main())


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)


import sys
sys.setrecursionlimit(500005)
stdin = sys.stdin
ni = lambda : int(ns())
na = lambda : list(map(int, stdin.readline().split()))
ns = lambda : stdin.readline().rstrip()
(n, m) = na()
hors = []
for i in range(n):
	hors.append(na())
vers = []
for j in range(m):
	vers.append(na())
xs = set()
for hor in hors:
	xs.add(hor[0])
	xs.add(hor[1])
for ver in vers:
	xs.add(ver[0])
xs = list(xs)
xs.sort()
ys = set()
for hor in hors:
	ys.add(hor[2])
for ver in vers:
	ys.add(ver[1])
	ys.add(ver[2])
ys = list(ys)
ys.sort()
upper = [-1] * ((len(xs) + 1) * (len(ys) + 1))
H = len(ys) + 1

def root(x):
	if upper[x] < 0:
		return x
	else:
		upper[x] = root(upper[x])
		return upper[x]

def equiv(x, y):
	return root(x) == root(y)

def unite(x, y):
	(x, y) = (root(x), root(y))
	if x != y:
		if upper[y] < upper[x]:
			(x, y) = (y, x)
		upper[x] += upper[y]
		upper[y] = x
	return x == y
import bisect
horb = [[0] * (len(xs) + 1) for _ in range(len(ys))]
for hor in hors:
	y = bisect.bisect_left(ys, hor[2])
	horb[y][bisect.bisect_left(xs, hor[0])] += 1
	horb[y][bisect.bisect_left(xs, hor[1])] -= 1
for i in range(len(ys)):
	for j in range(1, len(xs) + 1):
		horb[i][j] += horb[i][j - 1]
verb = [[0] * (len(ys) + 1) for _ in range(len(xs))]
for ver in vers:
	x = bisect.bisect_left(xs, ver[0])
	verb[x][bisect.bisect_left(ys, ver[1])] += 1
	verb[x][bisect.bisect_left(ys, ver[2])] -= 1
for i in range(len(xs)):
	for j in range(1, len(ys) + 1):
		verb[i][j] += verb[i][j - 1]
for i in range(len(xs) + 1):
	for j in range(len(ys) + 1):
		if i < len(xs) and j in (0, len(ys)):
			unite(i * H + j, (i + 1) * H + j)
		elif i < len(xs) and verb[i][j - 1] == 0:
			unite(i * H + j, (i + 1) * H + j)
		if j < len(ys) and i in (0, len(xs)):
			unite(i * H + j, i * H + j + 1)
		elif j < len(ys) and horb[j][i - 1] == 0:
			unite(i * H + j, i * H + j + 1)
ox = bisect.bisect_left(xs, 0)
oy = bisect.bisect_left(ys, 0)
if equiv(ox * H + oy, 0):
	print('INF')
else:
	S = 0
	for i in range(len(xs) + 1):
		for j in range(len(ys) + 1):
			if equiv(i * H + j, ox * H + oy):
				S += (xs[i] - xs[i - 1]) * (ys[j] - ys[j - 1])
	print(S)


def f_single_dot():
	import sys
	from collections import deque
	input = sys.stdin.readline
	(N, M) = [int(i) for i in input().split()]
	(x_set, y_set) = (set([0]), set([0]))
	vertical_lines = []
	for _ in range(N):
		(a, b, c) = [int(i) for i in input().split()]
		vertical_lines.append((a, b, c))
		x_set |= {a, b}
		y_set |= {c}
	horizontal_lines = []
	for _ in range(M):
		(d, e, f) = [int(i) for i in input().split()]
		horizontal_lines.append((d, e, f))
		x_set |= {d}
		y_set |= {e, f}
	x_set = sorted(x_set)
	y_set = sorted(y_set)
	x_encoded = {n: i * 2 for (i, n) in enumerate(x_set)}
	y_encoded = {n: i * 2 for (i, n) in enumerate(y_set)}
	x_length = [x_set[i // 2 + 1] - x_set[i // 2] if i % 2 else 0 for i in range(len(x_set) * 2 - 1)]
	y_length = [y_set[i // 2 + 1] - y_set[i // 2] if i % 2 else 0 for i in range(len(y_set) * 2 - 1)]
	(x_size, y_size) = (2 * len(x_set) - 1, 2 * len(y_set) - 1)
	grid = [[0] * y_size for _ in range(x_size)]
	for (a, b, c) in vertical_lines:
		(a, b, c) = (x_encoded[a], x_encoded[b], y_encoded[c])
		for x in range(a, b + 1):
			grid[x][c] = 1
	for (d, e, f) in horizontal_lines:
		(d, e, f) = (x_encoded[d], y_encoded[e], y_encoded[f])
		for y in range(e, f + 1):
			grid[d][y] = 1
	queue = deque()
	is_visited = [[0] * (y_size + 1) for _ in range(x_size + 1)]
	for (dx, dy) in ((-1, -1), (-1, 1), (1, 1), (1, -1)):
		(nx, ny) = (x_encoded[0] + dx, y_encoded[0] + dy)
		if 0 <= nx < x_size and 0 <= ny < y_size:
			queue.append((nx, ny))
			is_visited[nx][ny] = 1
	diff = ((-1, 0), (1, 0), (0, -1), (0, 1))
	ans = 0
	while queue:
		(x, y) = queue.pop()
		if x % 2 & y % 2:
			ans += x_length[x] * y_length[y]
		for (dx, dy) in diff:
			(nx, ny) = (x + dx, y + dy)
			(nnx, nny) = (nx + dx, ny + dy)
			if grid[nx][ny] == 0:
				if not (0 <= nnx < x_size and 0 <= nny < y_size):
					return 'INF'
				if not is_visited[nnx][nny]:
					queue.appendleft((nnx, nny))
					is_visited[nnx][nny] = 1
	return ans
print(f_single_dot())


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)


def f_single_dot():
	import sys
	from collections import deque
	input = sys.stdin.readline
	(N, M) = [int(i) for i in input().split()]
	(X, Y) = (set([0]), set([0]))
	(A, B, C) = ([0] * N, [0] * N, [0] * N)
	for i in range(N):
		(A[i], B[i], C[i]) = map(int, input().split())
		X |= {A[i], B[i]}
		Y |= {C[i]}
	(D, E, F) = ([0] * M, [0] * M, [0] * M)
	for i in range(M):
		(D[i], E[i], F[i]) = map(int, input().split())
		X |= {D[i]}
		Y |= {E[i], F[i]}
	X = sorted(X)
	Y = sorted(Y)
	(dictx, dicty) = ({n: i * 2 for (i, n) in enumerate(X)}, {n: i * 2 for (i, n) in enumerate(Y)})
	LX = [X[i // 2 + 1] - X[i // 2] if i % 2 else 0 for i in range(len(X) * 2 - 1)]
	LY = [Y[i // 2 + 1] - Y[i // 2] if i % 2 else 0 for i in range(len(Y) * 2 - 1)]
	c = [[0] * (len(X) * 2 - 1) for _ in range(len(Y) * 2 - 1)]
	for i in range(N):
		y = dicty[C[i]]
		for x in range(dictx[A[i]], dictx[B[i]] + 1):
			c[y][x] = 1
	for i in range(M):
		x = dictx[D[i]]
		for y in range(dicty[E[i]], dicty[F[i]] + 1):
			c[y][x] = 1
	que = deque()
	used = [[0] * len(X) * 2 for _ in range(len(Y) * 2)]
	dy = [1, 1, -1, -1]
	dx = [1, -1, 1, -1]
	for k in range(4):
		(nny, nnx) = (dicty[0] + dy[k], dictx[0] + dx[k])
		if 1 <= nny < len(Y) * 2 - 1 and 1 <= nnx < len(X) * 2 - 1:
			que.append((nny, nnx))
			used[nny][nnx] = 1
	ans = 0
	dy = [1, 0, -1, 0]
	dx = [0, 1, 0, -1]
	while que:
		(y, x) = que.popleft()
		if y % 2 and x % 2:
			ans += LY[y] * LX[x]
		for k in range(4):
			(ny, nx) = (y + dy[k], x + dx[k])
			(nny, nnx) = (ny + dy[k], nx + dx[k])
			if c[ny][nx] == 0:
				if nny < 0 or nny >= len(Y) * 2 - 1 or nnx < 0 or (nnx >= len(X) * 2 - 1):
					return 'INF'
				if not used[nny][nnx]:
					que.append((nny, nnx))
					used[nny][nnx] = 1
	return ans
print(f_single_dot())


import sys
import bisect
from collections import deque

def LI():
	return [int(x) for x in sys.stdin.readline().split()]

def LIR(n):
	return [LI() for i in range(n)]
M = 3 * 10 ** 9 + 1
M2 = (M - 10 ** 9) ** 2
(n, m) = LI()
p = LIR(n)
q = LIR(m)
fx = set([-M, 0, M])
fy = set([-M, 0, M])
for i in range(n):
	p[i][0] <<= 1
	p[i][1] <<= 1
	p[i][2] <<= 1
	(a, b, c) = p[i]
	fy.add(a)
	fy.add(b)
	fy.add(b + 1)
	fx.add(c)
	fx.add(c + 1)
for i in range(m):
	q[i][0] <<= 1
	q[i][1] <<= 1
	q[i][2] <<= 1
	(d, e, f) = q[i]
	fy.add(d)
	fy.add(d + 1)
	fx.add(e)
	fx.add(f)
	fx.add(f + 1)
fy = list(fy)
fx = list(fx)
fy.sort()
fx.sort()
s = [0] * len(fx) * len(fy)
for (a, b, c) in p:
	ai = bisect.bisect_left(fy, a)
	bi = bisect.bisect_left(fy, b)
	ci = bisect.bisect_left(fx, c)
	ka = ai * len(fx)
	kb = (bi + 1) * len(fx)
	s[ka + ci] += 1
	s[kb + ci] -= 1
	s[ka + ci + 1] -= 1
	s[kb + ci + 1] += 1
for (d, e, f) in q:
	di = bisect.bisect_left(fy, d)
	ei = bisect.bisect_left(fx, e)
	fi = bisect.bisect_left(fx, f)
	kd = di * len(fx)
	kdd = kd + len(fx)
	s[kd + ei] += 1
	s[kd + fi + 1] -= 1
	s[kdd + ei] -= 1
	s[kdd + fi + 1] += 1
for i in range(len(fy)):
	k = i * len(fx)
	for j in range(len(fx) - 1):
		ind = k + j
		s[ind + 1] += s[ind]
for i in range(len(fy) - 1):
	k = i * len(fx)
	for j in range(len(fx) - 1):
		ind = k + j
		s[ind + len(fx)] += s[ind]
sx = bisect.bisect_left(fx, 0)
sy = bisect.bisect_left(fy, 0)
(nh, nw) = (len(fy) - 1, len(fx) - 1)
for i in range(nw - 1):
	fx[i + 1] >>= 1
	fx[i] = fx[i + 1] - fx[i]
for i in range(nh - 1):
	fy[i + 1] >>= 1
	fy[i] = fy[i + 1] - fy[i]
ans = fx[sx] * fy[sy]
q = deque()
q.append((sy, sx))
f = [1] * nh * nw
f[sy * nw + sx] = 0
d = [(1, 0), (-1, 0), (0, 1), (0, -1)]
while q:
	(y, x) = q.popleft()
	for (dy, dx) in d:
		(ny, nx) = (y + dy, x + dx)
		if 0 <= ny < nh and 0 <= nx < nw:
			ind = ny * nw + nx
			if f[ind] and (not s[ind + ny]):
				if ny < 1 or nx < 1 or ny + 1 >= nh or (nx + 1 >= nw):
					print('INF')
					quit()
				ans += fx[nx] * fy[ny]
				f[ind] = 0
				q.append((ny, nx))
print(ans)


(N, M) = map(int, input().split())
ABC = [list(map(int, input().split())) for _ in [0] * N]
DEF = [list(map(int, input().split())) for _ in [0] * M]
X = [0] * 3003
Y = [0] * 3003
INF = 10 ** 9 + 10
X[-1] = -INF
Y[-1] = -INF
X[-2] = INF
Y[-2] = INF
i = 0
j = 0
for (a, b, c) in ABC:
	X[i] = a
	X[i + 1] = b
	Y[j] = c
	i += 2
	j += 1
for (d, e, f) in DEF:
	X[i] = d
	Y[j] = e
	Y[j + 1] = f
	i += 1
	j += 2
X = sorted(set(X))
Y = sorted(set(Y))
Xdict = {x: i for (i, x) in enumerate(X)}
Ydict = {y: i for (i, y) in enumerate(Y)}
nx = len(X)
ny = len(Y)
nxy = nx * ny
E = [[15] * nx for _ in [0] * ny]
E[0] = [7] * nx
E[-1] = [13] * nx
for i in range(ny):
	E[i][0] -= 4
	E[i][-1] -= 1
for (a, b, c) in ABC:
	y1 = Ydict[c]
	y0 = y1 - 1
	for x in range(Xdict[a], Xdict[b]):
		E[y0][x] &= 15 - 2
		E[y1][x] &= 15 - 8
for (d, e, f) in DEF:
	x1 = Xdict[d]
	x0 = x1 - 1
	for y in range(Ydict[e], Ydict[f]):
		E[y][x0] &= 15 - 1
		E[y][x1] &= 15 - 4
dX = [x2 - x for (x, x2) in zip(X, X[1:])]
dY = [y2 - y for (y, y2) in zip(Y, Y[1:])]
burst = False
x0 = Xdict[0]
y0 = Ydict[0]
ans = dX[x0] * dY[y0]
done = [[False] * nx for _ in [0] * ny]
done[y0][x0] = True
q = [(x0, y0)]
dxy = [(1, 0), (0, 1), (-1, 0), (0, -1)]
while q:
	qq = []
	for (x, y) in q:
		e = E[y][x]
		for i in range(4):
			if e >> i & 1 == 0:
				continue
			(dx, dy) = dxy[i]
			jx = x + dx
			jy = y + dy
			if done[jy][jx]:
				continue
			done[jy][jx] = True
			if jx == 0 or jx == nx - 1 or jy == 0 or (jy == ny - 1):
				burst = True
				ans = 'INF'
				qq = []
				break
			ans += dX[jx] * dY[jy]
			qq.append((jx, jy))
		if burst:
			break
	q = qq
print(ans)


(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)


import sys, bisect, string, math, time, functools, random, fractions
from heapq import heappush, heappop, heapify
from collections import deque, defaultdict, Counter
from itertools import permutations, combinations, groupby

def Golf():
	(n, *t) = map(int, open(0).read().split())

def I():
	return int(input())

def S_():
	return input()

def IS():
	return input().split()

def LS():
	return [i for i in input().split()]

def LI():
	return [int(i) for i in input().split()]

def LI_():
	return [int(i) - 1 for i in input().split()]

def NI(n):
	return [int(input()) for i in range(n)]

def NI_(n):
	return [int(input()) - 1 for i in range(n)]

def StoLI():
	return [ord(i) - 97 for i in input()]

def ItoS(n):
	return chr(n + 97)

def LtoS(ls):
	return ''.join([chr(i + 97) for i in ls])

def GI(V, E, ls=None, Directed=False, index=1):
	org_inp = []
	g = [[] for i in range(V)]
	FromStdin = True if ls == None else False
	for i in range(E):
		if FromStdin:
			inp = LI()
			org_inp.append(inp)
		else:
			inp = ls[i]
		if len(inp) == 2:
			(a, b) = inp
			c = 1
		else:
			(a, b, c) = inp
		if index == 1:
			a -= 1
			b -= 1
		aa = (a, c)
		bb = (b, c)
		g[a].append(bb)
		if not Directed:
			g[b].append(aa)
	return (g, org_inp)

def GGI(h, w, search=None, replacement_of_found='.', mp_def={'#': 1, '.': 0}, boundary=1):
	mp = [boundary] * (w + 2)
	found = {}
	for i in range(h):
		s = input()
		for char in search:
			if char in s:
				found[char] = (i + 1) * (w + 2) + s.index(char) + 1
				mp_def[char] = mp_def[replacement_of_found]
		mp += [boundary] + [mp_def[j] for j in s] + [boundary]
	mp += [boundary] * (w + 2)
	return (h + 2, w + 2, mp, found)

def TI(n):
	return GI(n, n - 1)

def bit_combination(n, base=2):
	rt = []
	for tb in range(base ** n):
		s = [tb // base ** bt % base for bt in range(n)]
		rt += [s]
	return rt

def gcd(x, y):
	if y == 0:
		return x
	if x % y == 0:
		return y
	while x % y != 0:
		(x, y) = (y, x % y)
	return y

def show(*inp, end='\n'):
	if show_flg:
		print(*inp, end=end)
YN = ['YES', 'NO']
Yn = ['Yes', 'No']
mo = 10 ** 9 + 7
inf = float('inf')
FourNb = [(-1, 0), (1, 0), (0, 1), (0, -1)]
EightNb = [(-1, 0), (1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)]
compas = dict(zip('WENS', FourNb))
cursol = dict(zip('LRUD', FourNb))
l_alp = string.ascii_lowercase
input = lambda : sys.stdin.readline().rstrip()

class Tree:

	def __init__(self, inp_size=None, ls=None, init=True, index=0):
		self.LCA_init_stat = False
		self.ETtable = []
		if init:
			if ls == None:
				self.stdin(inp_size, index=index)
			else:
				self.size = len(ls) + 1
				(self.edges, _) = GI(self.size, self.size - 1, ls, index=index)
		return

	def stdin(self, inp_size=None, index=1):
		if inp_size == None:
			self.size = int(input())
		else:
			self.size = inp_size
		(self.edges, _) = GI(self.size, self.size - 1, index=index)
		return

	def listin(self, ls, index=0):
		self.size = len(ls) + 1
		(self.edges, _) = GI(self.size, self.size - 1, ls, index=index)
		return

	def __str__(self):
		return str(self.edges)

	def dfs(self, x, func=lambda prv, nx, dist: prv + dist, root_v=0):
		q = deque()
		q.append(x)
		v = [-1] * self.size
		v[x] = root_v
		while q:
			c = q.pop()
			for (nb, d) in self.edges[c]:
				if v[nb] == -1:
					q.append(nb)
					v[nb] = func(v[c], nb, d)
		return v

	def EulerTour(self, x):
		q = deque()
		q.append(x)
		self.depth = [None] * self.size
		self.depth[x] = 0
		self.ETtable = []
		self.ETdepth = []
		self.ETin = [-1] * self.size
		self.ETout = [-1] * self.size
		cnt = 0
		while q:
			c = q.pop()
			if c < 0:
				ce = ~c
			else:
				ce = c
				for (nb, d) in self.edges[ce]:
					if self.depth[nb] == None:
						q.append(~ce)
						q.append(nb)
						self.depth[nb] = self.depth[ce] + 1
			self.ETtable.append(ce)
			self.ETdepth.append(self.depth[ce])
			if self.ETin[ce] == -1:
				self.ETin[ce] = cnt
			else:
				self.ETout[ce] = cnt
			cnt += 1
		return

	def LCA_init(self, root):
		self.EulerTour(root)
		self.st = SparseTable(self.ETdepth, init_func=min, init_idl=inf)
		self.LCA_init_stat = True
		return

	def LCA(self, root, x, y):
		if self.LCA_init_stat == False:
			self.LCA_init(root)
		(xin, xout) = (self.ETin[x], self.ETout[x])
		(yin, yout) = (self.ETin[y], self.ETout[y])
		a = min(xin, yin)
		b = max(xout, yout, xin, yin)
		id_of_min_dep_in_et = self.st.query_id(a, b + 1)
		return self.ETtable[id_of_min_dep_in_et]

class SparseTable:

	def __init__(self, ls, init_func=min, init_idl=float('inf')):
		self.func = init_func
		self.idl = init_idl
		self.size = len(ls)
		self.N0 = self.size.bit_length()
		self.table = [ls[:]]
		self.index = [list(range(self.size))]
		self.lg = [0] * (self.size + 1)
		for i in range(2, self.size + 1):
			self.lg[i] = self.lg[i >> 1] + 1
		for i in range(self.N0):
			tmp = [self.func(self.table[i][j], self.table[i][min(j + (1 << i), self.size - 1)]) for j in range(self.size)]
			tmp_id = [self.index[i][j] if self.table[i][j] == self.func(self.table[i][j], self.table[i][min(j + (1 << i), self.size - 1)]) else self.index[i][min(j + (1 << i), self.size - 1)] for j in range(self.size)]
			self.table += [tmp]
			self.index += [tmp_id]

	def query(self, l, r):
		if r > self.size:
			r = self.size
		N = self.lg[r - l]
		return self.func(self.table[N][l], self.table[N][max(0, r - (1 << N))])

	def query_id(self, l, r):
		if r > self.size:
			r = self.size
		N = self.lg[r - l]
		(a, b) = (self.index[N][l], self.index[N][max(0, r - (1 << N))])
		if self.table[0][a] == self.func(self.table[N][l], self.table[N][max(0, r - (1 << N))]):
			b = a
		return b

	def __str__(self):
		return str(self.table[0])

	def print(self):
		for i in self.table:
			print(*i)

class Comb:

	def __init__(self, n, mo=10 ** 9 + 7):
		self.fac = [0] * (n + 1)
		self.inv = [1] * (n + 1)
		self.fac[0] = 1
		self.fact(n)
		for i in range(1, n + 1):
			self.fac[i] = i * self.fac[i - 1] % mo
			self.inv[n] *= i
			self.inv[n] %= mo
		self.inv[n] = pow(self.inv[n], mo - 2, mo)
		for i in range(1, n):
			self.inv[n - i] = self.inv[n - i + 1] * (n - i + 1) % mo
		return

	def fact(self, n):
		return self.fac[n]

	def invf(self, n):
		return self.inv[n]

	def comb(self, x, y):
		if y < 0 or y > x:
			return 0
		return self.fac[x] * self.inv[x - y] * self.inv[y] % mo
show_flg = False
show_flg = True
ans = 0
inf = 1 << 65
(n, m) = LI()
X = [0, inf, -inf]
Y = [0, inf, -inf]
V = []
H = []
for i in range(n):
	(a, b, c) = LI()
	V.append(((a, b), c))
	Y.append(c)
	X.append(a)
	X.append(b)
n += 2
V.append(((-inf, inf), inf))
V.append(((-inf, inf), -inf))
for i in range(m):
	(a, b, c) = LI()
	H.append((a, (b, c)))
	X.append(a)
	Y.append(b)
	Y.append(c)
m += 2
H.append((inf, (-inf, inf)))
H.append((-inf, (-inf, inf)))
X.sort()
xdc = {}
c = 1
for j in sorted(set(X)):
	xdc[c] = j
	c += 1
nx = c - 1
Y.sort()
ydc = {}
c = 1
for j in sorted(set(Y)):
	ydc[c] = j
	c += 1
ny = c - 1
xdcr = dict(zip(xdc.values(), xdc.keys()))
ydcr = dict(zip(ydc.values(), ydc.keys()))
mpy = [[0] * (nx + 1 + 1) for i in range(ny + 1 + 1)]
mpx = [[0] * (nx + 1 + 1) for i in range(ny + 1 + 1)]
for ((a, b), c) in V:
	mpx[ydcr[c]][xdcr[a]] += 1
	mpx[ydcr[c]][xdcr[b]] += -1
for i in range(ny + 1):
	for j in range(nx):
		mpx[i][j + 1] += mpx[i][j]
for (d, (e, f)) in H:
	mpy[ydcr[e]][xdcr[d]] += 1
	mpy[ydcr[f]][xdcr[d]] += -1
for j in range(nx + 1):
	for i in range(ny):
		mpy[i + 1][j] += mpy[i][j]
v = [[0] * (nx + 1) for i in range(ny + 1)]
q = deque()
q.append((xdcr[0], ydcr[0]))
v[ydcr[0]][xdcr[0]] = 1
while q:
	(cx, cy) = q.popleft()
	ans += (xdc[cx] - xdc[cx + 1]) * (ydc[cy] - ydc[cy + 1])
	for (dx, dy) in FourNb:
		nbx = cx + dx
		nby = cy + dy
		if not 0 <= nbx < nx or not 0 <= nby < ny or v[nby][nbx] == 1:
			continue
		if dy != 0:
			if mpx[cy + (dy + 1) // 2][cx] == 0:
				q.append((nbx, nby))
				v[nby][nbx] = 1
		elif mpy[cy][cx + (dx + 1) // 2] == 0:
			q.append((nbx, nby))
			v[nby][nbx] = 1
if ans >= inf:
	ans = 'INF'
print(ans)


def main():
	import sys
	readline = sys.stdin.readline
	from collections import deque
	from bisect import bisect_left
	(N, M) = map(int, input().split())
	tate = []
	yoko = []
	X = set()
	Y = set()
	for _ in range(N):
		(A, B, C) = map(int, readline().split())
		X.add(A)
		X.add(B)
		Y.add(C)
		tate.append((C, A, B))
	for _ in range(M):
		(D, E, F) = map(int, readline().split())
		X.add(D)
		Y.add(E)
		Y.add(F)
		yoko.append((D, E, F))
	X = sorted(list(X))
	Y = sorted(list(Y))
	H = len(X)
	W = len(Y)
	wall = [[15] * W for _ in range(H)]
	for (c, a, b) in tate:
		ia = bisect_left(X, a)
		ib = bisect_left(X, b)
		jc = bisect_left(Y, c)
		for i in range(ia, ib):
			wall[i][jc - 1] &= 15 - (1 << 1)
			wall[i][jc] &= 15 - (1 << 3)
	for (d, e, f) in yoko:
		id = bisect_left(X, d)
		je = bisect_left(Y, e)
		jf = bisect_left(Y, f)
		for j in range(je, jf):
			wall[id - 1][j] &= 15 - (1 << 2)
			wall[id][j] &= 15 - (1 << 0)
	q = deque()
	x0 = bisect_left(X, 0) - (0 not in X)
	y0 = bisect_left(Y, 0) - (0 not in Y)
	if x0 == H - 1 or y0 == W - 1:
		print('INF')
		exit()
	path = [True] * (W * H)
	path[x0 * W + y0] = False
	q.append((x0, y0))
	direction = ((-1, 0), (0, 1), (1, 0), (0, -1))
	cnt = 0
	while q:
		(x, y) = q.popleft()
		cnt += (X[x + 1] - X[x]) * (Y[y + 1] - Y[y])
		for (i, (dx, dy)) in enumerate(direction):
			if wall[x][y] & 1 << i:
				nx = x + dx
				ny = y + dy
				if 0 <= nx < H - 1 and 0 <= ny < W - 1:
					if path[nx * W + ny]:
						path[nx * W + ny] = False
						q.append((nx, ny))
				else:
					print('INF')
					exit()
	print(cnt)
main()


import sys
from collections import deque
input = sys.stdin.readline

def compress_coordinate(x: list, key=None, reverse=False):
	zipped = {}
	unzipped = {}
	for (i, xi) in enumerate(sorted(set(x), key=key, reverse=reverse)):
		zipped[xi] = i
		unzipped[i] = xi
	return (zipped, unzipped)
(n, m) = map(int, input().split())
line_v = [tuple(map(int, input().split())) for _ in range(n)]
line_h = [tuple(map(int, input().split())) for _ in range(m)]
INF = 10 ** 9 + 10
dx = [+1, 0, -1, 0]
dy = [0, +1, 0, -1]
x_list = [-INF, 0, INF]
y_list = [-INF, 0, INF]
for (x1, x2, y) in line_v:
	x_list.append(x1)
	x_list.append(x2)
	y_list.append(y)
for (x, y1, y2) in line_h:
	x_list.append(x)
	y_list.append(y1)
	y_list.append(y2)
(x_zipped, x_unzipped) = compress_coordinate(x_list)
(y_zipped, y_unzipped) = compress_coordinate(y_list)
nx = len(x_zipped)
ny = len(y_zipped)
v_ng = [[0] * (ny + 1) for _ in range(nx + 1)]
h_ng = [[0] * (ny + 1) for _ in range(nx + 1)]
for (x1, x2, y) in line_v:
	x1 = x_zipped[x1]
	x2 = x_zipped[x2]
	y = y_zipped[y]
	v_ng[x1][y] += 1
	v_ng[x2][y] -= 1
for (x, y1, y2) in line_h:
	x = x_zipped[x]
	y1 = y_zipped[y1]
	y2 = y_zipped[y2]
	h_ng[x][y1] += 1
	h_ng[x][y2] -= 1
for x in range(nx):
	for y in range(ny):
		v_ng[x + 1][y] += v_ng[x][y]
		h_ng[x][y + 1] += h_ng[x][y]
grid = [[False] * (ny + 1) for _ in range(nx + 1)]
q = deque([(x_zipped[0], y_zipped[0])])
while q:
	(x0, y0) = q.popleft()
	if grid[x0][y0]:
		continue
	grid[x0][y0] = True
	for k in range(4):
		x1 = x0 + dx[k]
		y1 = y0 + dy[k]
		if x1 < 0 or x1 >= nx or y1 < 0 or (y1 >= ny):
			continue
		if grid[x1][y1]:
			continue
		if k == 0 and h_ng[x1][y1] == 0:
			q.append((x1, y1))
		elif k == 2 and h_ng[x0][y0] == 0:
			q.append((x1, y1))
		elif k == 1 and v_ng[x1][y1] == 0:
			q.append((x1, y1))
		elif k == 3 and v_ng[x0][y0] == 0:
			q.append((x1, y1))
if grid[0][0]:
	ans = 'INF'
else:
	ans = 0
	for x in range(nx):
		for y in range(ny):
			if grid[x][y]:
				ans += (x_unzipped[x + 1] - x_unzipped[x]) * (y_unzipped[y + 1] - y_unzipped[y])
print(ans)


import sys
from collections import deque
input = sys.stdin.readline
(N, M) = map(int, input().split())
TATE = [tuple(map(int, input().split())) for i in range(N)]
YOKO = [tuple(map(int, input().split())) for i in range(M)]
T = [-1 << 63, (-1 << 63) + 1, 0, 1 << 63, (1 << 63) + 1]
Y = [-1 << 63, (-1 << 63) + 1, 0, 1 << 63, (1 << 63) + 1]
for (a, b, c) in TATE:
	T.append(a)
	T.append(b)
	Y.append(c)
for (d, e, f) in YOKO:
	T.append(d)
	Y.append(e)
	Y.append(f)
T = sorted(set(T))
Y = sorted(set(Y))
BT = [T[0]]
BY = [Y[0]]
for i in range(1, len(T)):
	BT.append(T[i] - T[i - 1])
	BT.append(T[i])
for i in range(1, len(Y)):
	BY.append(Y[i] - Y[i - 1])
	BY.append(Y[i])
TDICT = dict()
YDICT = dict()
LBT = len(BT)
LBY = len(BY)
for i in range(LBT):
	if i % 2 == 0:
		TDICT[BT[i]] = i
for i in range(LBY):
	if i % 2 == 0:
		YDICT[BY[i]] = i
MAP = [[0] * (LBY + 1) for i in range(LBT + 1)]
for (a, b, c) in TATE:
	t0 = TDICT[a]
	t1 = TDICT[b]
	y = YDICT[c]
	MAP[t0][y] += 1
	MAP[t0][y + 1] -= 1
	MAP[t1 + 1][y] -= 1
	MAP[t1 + 1][y + 1] += 1
for (d, e, f) in YOKO:
	t = TDICT[d]
	y0 = YDICT[e]
	y1 = YDICT[f]
	MAP[t][y0] += 1
	MAP[t + 1][y0] -= 1
	MAP[t][y1 + 1] -= 1
	MAP[t + 1][y1 + 1] += 1
for i in range(LBT):
	for j in range(1, LBY):
		MAP[i][j] += MAP[i][j - 1]
for i in range(LBY):
	for j in range(1, LBT):
		MAP[j][i] += MAP[j - 1][i]
Q = deque()
(x, y) = (TDICT[0], YDICT[0])
Q.append((x - 1, y - 1))
Q.append((x + 1, y - 1))
Q.append((x - 1, y + 1))
Q.append((x + 1, y + 1))
MAP[x - 1][y - 1] = MAP[x + 1][y - 1] = MAP[x - 1][y + 1] = MAP[x + 1][y + 1] = 1
ANS = BT[x - 1] * BY[y - 1] + BT[x + 1] * BY[y - 1] + BT[x - 1] * BY[y + 1] + BT[x + 1] * BY[y + 1]
while Q:
	(x, y) = Q.pop()
	if MAP[x + 1][y] == 0 and MAP[x + 2][y] == 0:
		MAP[x + 2][y] = 1
		Q.append((x + 2, y))
		ANS += BT[x + 2] * BY[y]
	if MAP[x - 1][y] == 0 and MAP[x - 2][y] == 0:
		MAP[x - 2][y] = 1
		Q.append((x - 2, y))
		ANS += BT[x - 2] * BY[y]
	if MAP[x][y + 1] == 0 and MAP[x][y + 2] == 0:
		MAP[x][y + 2] = 1
		Q.append((x, y + 2))
		ANS += BT[x] * BY[y + 2]
	if MAP[x][y - 1] == 0 and MAP[x][y - 2] == 0:
		MAP[x][y - 2] = 1
		Q.append((x, y - 2))
		ANS += BT[x] * BY[y - 2]
	if ANS >= 1 << 62:
		print('INF')
		sys.exit()
print(ANS)


import sys
readline = sys.stdin.readline
read = sys.stdin.read
(n, m) = [int(i) for i in readline().split()]
tate = [[int(i) for i in readline().split()] for _ in range(n)]
yoko = [[int(i) for i in readline().split()] for _ in range(m)]
INF = 10 ** 9 + 5
hcoord = {-INF, 0, INF}
wcoord = {-INF, 0, INF}
for (a, b, c) in tate:
	hcoord.add(a)
	hcoord.add(b)
	wcoord.add(c)
for (d, e, f) in yoko:
	hcoord.add(d)
	wcoord.add(e)
	wcoord.add(f)
hcoord = list(sorted(hcoord))
wcoord = list(sorted(wcoord))
zaatu_x = {a: i for (i, a) in enumerate(sorted(hcoord))}
zaatu_y = {a: i for (i, a) in enumerate(sorted(wcoord))}
P = len(hcoord)
Q = len(wcoord)
ok_h = [[1 for y in range(Q - 1)] for x in range(P - 1)]
ok_w = [[1 for y in range(Q - 1)] for x in range(P - 1)]
for y in range(Q - 1):
	ok_h[P - 2][y] = 0
for x in range(P - 1):
	ok_w[x][Q - 2] = 0
for (a, b, c) in tate:
	xa = zaatu_x[a]
	xb = zaatu_x[b]
	yc = zaatu_y[c]
	for i in range(xa, xb):
		ok_w[i][yc - 1] = 0
for (d, e, f) in yoko:
	ye = zaatu_y[e]
	yf = zaatu_y[f]
	xd = zaatu_x[d]
	for i in range(ye, yf):
		ok_h[xd - 1][i] = 0
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]
x0 = zaatu_x[0]
y0 = zaatu_y[0]
used = [[0 for y in range(Q - 1)] for x in range(P - 1)]
from collections import deque
q = deque([(x0, y0)])
used[x0][y0] = 1
while q:
	(x, y) = q.popleft()
	for i in range(4):
		nx = x + dx[i]
		ny = y + dy[i]
		if nx < 0 or ny < 0 or nx >= P - 1 or (ny >= Q - 1):
			continue
		if i == 0 and ok_h[x][y] == 0:
			continue
		if i == 2 and ok_h[nx][ny] == 0:
			continue
		if i == 1 and ok_w[x][y] == 0:
			continue
		if i == 3 and ok_w[nx][ny] == 0:
			continue
		if used[nx][ny] == 0:
			used[nx][ny] = 1
			q.append((nx, ny))
if used[0][0] == 1:
	print('INF')
else:
	ans = 0
	for i in range(P - 1):
		for j in range(Q - 1):
			if used[i][j] == 1:
				ans += (hcoord[i + 1] - hcoord[i]) * (wcoord[j + 1] - wcoord[j])
	print(ans)


(N, M) = map(int, input().split())
X = set()
Y = set()
ABC = []
for _ in range(N):
	(A, B, C) = map(int, input().split())
	X.add(A)
	X.add(B)
	Y.add(C)
	ABC.append((A, B, C))
DEF = []
for _ in range(M):
	(D, E, F) = map(int, input().split())
	X.add(D)
	Y.add(E)
	Y.add(F)
	DEF.append((D, E, F))
XL = sorted(list(X))
YL = sorted(list(Y))
XD = {k: v for (v, k) in enumerate(XL)}
YD = {k: v for (v, k) in enumerate(YL)}
nX = len(XL) + 1
nY = len(YL) + 1
S = [[False] * nY for _ in range(nX)]
T = [[15] * nY for _ in range(nX)]
for (a, b, c) in ABC:
	xbgn = XD[a] + 1
	xend = XD[b]
	yu = YD[c]
	yd = yu + 1
	for x in range(xbgn, xend + 1):
		T[x][yu] -= 4
		T[x][yd] -= 8
for (d, e, f) in DEF:
	ybgn = YD[e] + 1
	yend = YD[f]
	xl = XD[d]
	xr = xl + 1
	for y in range(ybgn, yend + 1):
		T[xl][y] -= 1
		T[xr][y] -= 2
x0 = 0
while XL[x0] < 0 and x0 < nX - 2:
	x0 += 1
y0 = 0
while YL[y0] < 0 and y0 < nY - 2:
	y0 += 1
queue = [(x0, y0)]
ans = 0
while queue:
	queue_new = []
	for (qx, qy) in queue:
		if S[qx][qy]:
			continue
		S[qx][qy] = True
		if qx == 0 or qy == 0 or qx == nX - 1 or (qy == nY - 1):
			print('INF')
			exit()
		ans += (XL[qx] - XL[qx - 1]) * (YL[qy] - YL[qy - 1])
		t = T[qx][qy]
		if t & 1:
			queue_new.append((qx + 1, qy))
		if t & 2:
			queue_new.append((qx - 1, qy))
		if t & 4:
			queue_new.append((qx, qy + 1))
		if t & 8:
			queue_new.append((qx, qy - 1))
	queue = queue_new
print(ans)


class UnionFind:

	def __init__(self, n):
		self.parent = list(range(n))
		self.size = [1] * n

	def root(self, x):
		while self.parent[x] != x:
			self.parent[x] = self.parent[self.parent[x]]
			x = self.parent[x]
		return x

	def merge(self, x, y):
		(x, y) = (self.root(x), self.root(y))
		if x == y:
			return False
		if self.size[x] < self.size[y]:
			(x, y) = (y, x)
		self.size[x] += self.size[y]
		self.parent[y] = x
		return True

	def issame(self, x, y):
		return self.root(x) == self.root(y)

	def getsize(self, x):
		return self.size[self.root(x)]
import sys
readline = sys.stdin.readline
read = sys.stdin.read
(n, m) = map(int, readline().split())
yoko = [list(map(int, readline().split())) for _ in range(n)]
tate = [list(map(int, readline().split())) for _ in range(m)]
INF = 10 ** 9 + 5
xcoord = [-INF, 0, INF]
ycoord = [-INF, 0, INF]
for (a, b, c) in yoko:
	xcoord.append(a)
	xcoord.append(b)
	ycoord.append(c)
for (d, e, f) in tate:
	ycoord.append(e)
	ycoord.append(f)
	xcoord.append(d)
xcoord = list(sorted(set(xcoord)))
ycoord = list(sorted(set(ycoord)))
zaatu_x = {a: i for (i, a) in enumerate(xcoord)}
zaatu_y = {a: i for (i, a) in enumerate(ycoord)}
P = len(xcoord)
Q = len(ycoord)
QQ = Q - 1
ok_up = [[0] * P for _ in range(Q)]
ok_ri = [[0] * Q for _ in range(P)]
for (a, b, c) in yoko:
	xa = zaatu_x[a]
	xb = zaatu_x[b]
	yc = zaatu_y[c]
	ok_up[yc - 1][xa] += 1
	ok_up[yc - 1][xb] -= 1
for (d, e, f) in tate:
	ye = zaatu_y[e]
	yf = zaatu_y[f]
	xd = zaatu_x[d]
	ok_ri[xd - 1][ye] += 1
	ok_ri[xd - 1][yf] -= 1
from itertools import accumulate
for i in range(Q):
	ok_up[i] = list(accumulate(ok_up[i]))
for j in range(P):
	ok_ri[j] = list(accumulate(ok_ri[j]))
UF = UnionFind((P - 1) * QQ)
for i in range(P - 1):
	for j in range(Q - 2):
		v = i * QQ + j
		if ok_up[j][i] == 0:
			UF.merge(v, v + 1)
for i in range(P - 2):
	for j in range(Q - 1):
		v = i * QQ + j
		if ok_ri[i][j] == 0:
			UF.merge(v, v + QQ)
x0 = zaatu_x[0]
y0 = zaatu_y[0]
r = UF.root(x0 * QQ + y0)
if UF.root(0) == r:
	print('INF')
else:
	ans = sum(((xcoord[i + 1] - xcoord[i]) * (ycoord[j + 1] - ycoord[j]) for i in range(P - 1) for j in range(Q - 1) if UF.root(i * QQ + j) == r))
	print(ans)


import sys
input = sys.stdin.readline
(N, M) = map(int, input().split())
ABC = [tuple(map(int, input().split())) for i in range(N)]
DEF = [tuple(map(int, input().split())) for i in range(M)]
INF = float('inf')

def solve():
	xs = set([-INF, 0, INF])
	ys = set([-INF, 0, INF])
	for (a, b, c) in ABC:
		xs.add(a)
		xs.add(b)
		ys.add(c)
	for (d, e, f) in DEF:
		xs.add(d)
		ys.add(e)
		ys.add(f)
	xs = sorted(xs)
	ys = sorted(ys)
	xd = {x: i * 2 for (i, x) in enumerate(xs)}
	yd = {y: i * 2 for (i, y) in enumerate(ys)}
	W = len(xs) * 2 - 1
	H = len(ys) * 2 - 1
	S = [[0] * W for _ in range(H)]
	for y in (0, -1):
		for x in range(W):
			S[y][x] = 1
	for x in (0, -1):
		for y in range(H):
			S[y][x] = 1
	for (a, b, c) in ABC:
		for x in range(xd[a], xd[b] + 1):
			S[yd[c]][x] = 1
	for (d, e, f) in DEF:
		for y in range(yd[e], yd[f] + 1):
			S[y][xd[d]] = 1
	from collections import deque
	(sx, sy) = (xd[0] + 1, yd[0] + 1)
	q = deque([(sx, sy)])
	visited = [[0] * W for _ in range(H)]
	visited[sy][sx] = 1
	dxy = [(0, 1), (1, 0), (0, -1), (-1, 0)]
	ans = (xs[sx // 2 + 1] - xs[sx // 2]) * (ys[sy // 2 + 1] - ys[sy // 2])
	while q:
		(x, y) = q.popleft()
		for (dx, dy) in dxy:
			(nx, ny) = (x + dx, y + dy)
			if S[ny][nx] == 1:
				continue
			(nnx, nny) = (nx + dx, ny + dy)
			if visited[nny][nnx]:
				continue
			visited[nny][nnx] = 1
			q.append((nnx, nny))
			(tx, ty) = (nx, nny) if nx % 2 else (nnx, ny)
			assert tx % 2 and ty % 2
			w = xs[tx // 2 + 1] - xs[tx // 2]
			h = ys[ty // 2 + 1] - ys[ty // 2]
			ans += w * h
			if ans == INF:
				print('INF')
				exit()
	print(ans)
solve()


import sys
(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)
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(1, col):
	ri0 = row * (i - 1)
	ri1 = row * i
	for j in range(1, row):
		banned_up[ri1 + j] += banned_up[ri1 + j - 1]
		banned_down[ri1 + j] += banned_down[ri1 + j - 1]
		banned_left[ri1 + j] += banned_left[ri0 + j]
		banned_right[ri1 + j] += banned_right[ri0 + j]
s = row * y_dict[0] + x_dict[0]
enable = [-1] * row + ([-1] + [0] * (row - 2) + [-1]) * (col - 2) + [-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)
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)


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')


import sys
from collections import deque
from bisect import bisect_left

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

def main():
	(N, M) = map(int, input().split())
	X = set([])
	Y = set([])
	mapX = {}
	mapY = {}
	horizontal = []
	vertical = []
	for _ in range(N):
		(a, b, c) = map(int, input().split())
		X.add(a)
		X.add(b)
		Y.add(c)
		vertical.append((a, b, c))
	for _ in range(M):
		(d, e, f) = map(int, input().split())
		X.add(d)
		Y.add(e)
		Y.add(f)
		horizontal.append((d, e, f))
	X = list(X)
	Y = list(Y)
	X.sort()
	Y.sort()
	for (i, x) in enumerate(X):
		mapX[x] = i
	for (i, y) in enumerate(Y):
		mapY[y] = i
	h = len(mapX) * 2
	w = len(mapY) * 2
	grid = [[0] * w for _ in range(h)]
	for i in range(N):
		a = mapX[vertical[i][0]] * 2
		b = mapX[vertical[i][1]] * 2
		c = mapY[vertical[i][2]] * 2
		for x in range(a, b + 1):
			grid[x][c] = -1
	for j in range(M):
		d = mapX[horizontal[j][0]] * 2
		e = mapY[horizontal[j][1]] * 2
		f = mapY[horizontal[j][2]] * 2
		for y in range(e, f + 1):
			grid[d][y] = -1
	start_x = bisect_left(X, 0) * 2 - 1
	start_y = bisect_left(Y, 0) * 2 - 1
	if start_x < 0 or start_y < 0 or start_x >= h - 1 or (start_y >= w - 1):
		print('INF')
		return
	grid[start_x][start_y] = 1
	dx = [-1, 0, 1, 0]
	dy = [0, -1, 0, 1]
	ans = 0
	q = deque([(start_x, start_y)])
	grid[start_x][start_y] = 1
	while q:
		(x, y) = q.popleft()
		ans += (X[x // 2 + 1] - X[x // 2]) * (Y[y // 2 + 1] - Y[y // 2])
		for i in range(4):
			(nx, ny) = (x + dx[i], y + dy[i])
			if nx == h - 2 and grid[nx][ny] == 0 or ny == w:
				print('INF')
				return
			if grid[nx][ny] != 0:
				continue
			(nnx, nny) = (nx + dx[i], ny + dy[i])
			if nnx < 0 or nny < 0 or nnx == h - 1 or (nny == w - 1):
				print('INF')
				return
			if grid[nnx][nny] != 0:
				continue
			grid[nnx][nny] = 1
			q.append((nnx, nny))
	print(ans)
main()


import sys
import operator
from itertools import repeat, islice
from functools import partial, reduce
from typing import Iterable, MutableSequence, Optional, Tuple, Union
Indices = Union[int, slice, Tuple[Union[int, slice]]]

class nd(list):

	def __getitem__(self, indices: Union[int, slice, Tuple[Union[int, slice]]]):
		if isinstance(indices, (int, slice)):
			return super().__getitem__(indices)
		else:
			return reduce(operator.getitem, indices, self)

	def __setitem__(self, indices: Union[int, slice, Tuple[Union[int, slice]]], value):
		if isinstance(indices, (int, slice)):
			super().__setitem__(indices, value)
		else:
			(*rest_indices, last_index) = indices
			self[rest_indices][last_index] = value

	def fill(self, value):
		for i in range(len(self)):
			element = super().__getitem__(i)
			if isinstance(element, nd):
				element.apply_inplace(value)
			else:
				super().__setitem__(i, value)

	def apply(self, func):
		return type(self)((element.apply(func) if isinstance(element, nd) else func(element) for element in self))

	def apply_inplace(self, func):
		for i in range(len(self)):
			element = super().__getitem__(i)
			if isinstance(element, nd):
				element.apply_inplace(func)
			else:
				super().__setitem__(i, func(element))

	def operate(self, other, operator):
		if not isinstance(other, list):
			other = repeat(other)
		return type(self)((element.operate(other_element, operator) if isinstance(element, nd) else operator(element, other_element) for (element, other_element) in zip(self, other)))

	def roperate(self, other, operator):
		if not isinstance(other, list):
			other = repeat(other)
		return type(self)((element.roperate(other_element, operator) if isinstance(element, nd) else operator(other_element, element) for (element, other_element) in zip(self, other)))

	def ioperate(self, other, operator):
		if not isinstance(other, list):
			other = repeat(other)
		for (i, (element, other_element)) in enumerate(zip(self, other)):
			if isinstance(element, nd):
				element.ioperate(other_element, operator)
			else:
				super().__setitem__(i, operator(element, other_element))
		return self

	def rioperate(self, other, operator):
		if not isinstance(other, list):
			other = repeat(other)
		for (i, (element, other_element)) in enumerate(zip(self, other)):
			if isinstance(element, nd):
				element.rioperate(other_element, operator)
			else:
				super().__setitem__(i, operator(other_element, element))
		return self

	def __add__(self, other):
		return self.operate(other, operator.add)

	def __radd__(self, other):
		return self.roperate(other, operator.add)

	def __iadd__(self, other):
		return self.ioperate(other, operator.add)

	def __sub__(self, other):
		return self.operate(other, operator.sub)

	def __rsub__(self, other):
		return self.roperate(other, operator.sub)

	def __isub__(self, other):
		return self.ioperate(other, operator.sub)

	def __mul__(self, other):
		return self.operate(other, operator.mul)

	def __rmul__(self, other):
		return self.roperate(other, operator.mul)

	def __imul__(self, other):
		return self.ioperate(other, operator.mul)

	def __matmul__(self, other):
		return self.operate(other, operator.matmul)

	def __rmatmul__(self, other):
		return self.roperate(other, operator.matmul)

	def __imatmul__(self, other):
		return self.ioperate(other, operator.matmul)

	def __truediv__(self, other):
		return self.operate(other, operator.truediv)

	def __rtruediv__(self, other):
		return self.roperate(other, operator.truediv)

	def __itruediv__(self, other):
		return self.ioperate(other, operator.truediv)

	def __floordiv__(self, other):
		return self.operate(other, operator.floordiv)

	def __rfloordiv__(self, other):
		return self.roperate(other, operator.floordiv)

	def __ifloordiv__(self, other):
		return self.ioperate(other, operator.floordiv)

	def __mod__(self, other):
		return self.operate(other, operator.mod)

	def __rmod__(self, other):
		return self.roperate(other, operator.mod)

	def __imod__(self, other):
		return self.ioperate(other, operator.mod)

	def __divmod__(self, other):
		return self.operate(other, operator.divmod)

	def __rdivmod__(self, other):
		return self.roperate(other, operator.divmod)

	def __idivmod__(self, other):
		return self.ioperate(other, operator.divmod)

	def __pow__(self, other):
		return self.operate(other, operator.pow)

	def __rpow__(self, other):
		return self.roperate(other, operator.pow)

	def __ipow__(self, other):
		return self.ioperate(other, operator.pow)

	def __lshift__(self, other):
		return self.operate(other, operator.lshift)

	def __rlshift__(self, other):
		return self.roperate(other, operator.lshift)

	def __ilshift__(self, other):
		return self.ioperate(other, operator.lshift)

	def __rshift__(self, other):
		return self.operate(other, operator.rshift)

	def __rrshift__(self, other):
		return self.roperate(other, operator.rshift)

	def __irshift__(self, other):
		return self.ioperate(other, operator.rshift)

	def __and__(self, other):
		return self.operate(other, operator.and_)

	def __rand__(self, other):
		return self.roperate(other, operator.and_)

	def __iand__(self, other):
		return self.ioperate(other, operator.and_)

	def __xor__(self, other):
		return self.operate(other, operator.xor)

	def __rxor__(self, other):
		return self.roperate(other, operator.xor)

	def __ixor__(self, other):
		return self.ioperate(other, operator.xor)

	def __or__(self, other):
		return self.operate(other, operator.or_)

	def __ror__(self, other):
		return self.roperate(other, operator.or_)

	def __ior__(self, other):
		return self.ioperate(other, operator.or_)

	def __neg__(self, other):
		return self.apply(other, operator.neg)

	def __pos__(self, other):
		return self.apply(other, operator.pos)

	def __abs__(self, other):
		return self.apply(other, operator.abs)

	def __invert__(self, other):
		return self.apply(other, operator.invert)

	def __lt__(self, other):
		return self.operate(other, operator.lt)

	def __le__(self, other):
		return self.operate(other, operator.le)

	def __eq__(self, other):
		return self.operate(other, operator.eq)

	def __ne__(self, other):
		return self.operate(other, operator.ne)

	def __gt__(self, other):
		return self.operate(other, operator.gt)

	def __ge__(self, other):
		return self.operate(other, operator.ge)

	@classmethod
	def full(cls, fill_value, shape: Union[int, Tuple[int], Iterable[int]]):
		if isinstance(shape, int):
			return cls(repeat(fill_value, shape))
		elif not isinstance(shape, tuple):
			shape = tuple(shape)
		if len(shape) == 1:
			return cls(repeat(fill_value, shape[0]))
		else:
			return cls(map(partial(cls.full, fill_value), repeat(shape[1:], shape[0])))

	@classmethod
	def fromiter(cls, iterable, ndim=1):
		if ndim == 1:
			return cls(iterable)
		else:
			return cls((cls.fromiter(element, ndim - 1) for element in 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)

	@classmethod
	def partial_map(cls, func, *left_args, **left_kwargs):

		def nd_func(a, *right_args, **right_kwargs):
			return cls.fromiter((func(*left_args, v, *right_args, **left_kwargs, **right_kwargs) for v in a))
		return nd_func

	@classmethod
	def vectorize(cls, func, *left_args, **left_kwargs):

		def nd_func(a: nd, *right_args, **right_kwargs):
			return a.apply(lambda v: func(*left_args, v, *right_args, **left_kwargs, **right_kwargs))
		return nd_func

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 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)
C = nd.partial_map(bisect_right, xs)(C)
A = nd.partial_map(bisect_left, ys)(A)
A += 1
B = nd.partial_map(bisect_right, ys)(B)
D = nd.partial_map(bisect_right, ys)(D)
E = nd.partial_map(bisect_left, xs)(E)
E += 1
F = nd.partial_map(bisect_right, xs)(F)
for (a, b, c) in zip(A, B, C):
	for y in range(a, b):
		x_guard[c, y] = True
for (d, e, f) in zip(D, E, F):
	for x in range(e, f):
		y_guard[x, d] = True
cow = (bisect_right(xs, 0), bisect_right(ys, 0))
nexts = deque([cow])
visited = nd.zeros((len(xs) + 1, len(ys) + 1), type=bool)
area = 0
while nexts:
	(xi, yi) = nexts.popleft()
	if visited[xi, yi]:
		continue
	visited[xi, yi] = True
	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]:
			nexts.append((xi - 1, yi))
		if not x_guard[xi + 1, yi]:
			nexts.append((xi + 1, yi))
		if not y_guard[xi, yi]:
			nexts.append((xi, yi - 1))
		if not y_guard[xi, yi + 1]:
			nexts.append((xi, yi + 1))
	else:
		area = 'INF'
		break
print(area)


import math
import queue
import bisect
from collections import deque, defaultdict
import heapq as hpq
from sys import stdin, setrecursionlimit
ipt = stdin.readline
setrecursionlimit(10 ** 7)

def main():
	dir = [(-1, 0), (1, 0), (0, -1), (0, 1)]
	(n, m) = map(int, ipt().split())
	xb = []
	yb = []
	xs = []
	ys = []
	for i in range(n):
		(a, b, c) = map(int, ipt().split())
		xb.append((a, b, c))
		xs.append(a)
		xs.append(b)
		ys.append(c)
	for j in range(m):
		(d, e, f) = map(int, ipt().split())
		yb.append((d, e, f))
		xs.append(d)
		ys.append(e)
		ys.append(f)
	xs = sorted(list(set(xs)))
	ys = sorted(list(set(ys)))
	lx = len(xs)
	ly = len(ys)
	dix = dict()
	diy = dict()
	for (i, xi) in enumerate(xs):
		dix[xi] = i
	for (i, yi) in enumerate(ys):
		diy[yi] = i
	brd = [[1] * (ly * 2 - 1) for _ in range(lx * 2 - 1)]
	for (a, b, c) in xb:
		xa = dix[a]
		xb = dix[b]
		xc = diy[c]
		for i in range(xa, xb):
			brd[2 * i + 1][xc * 2] = 0
	for (d, e, f) in yb:
		xd = dix[d]
		xe = diy[e]
		xf = diy[f]
		for i in range(xe, xf):
			brd[xd * 2][2 * i + 1] = 0
	for (i, xi) in enumerate(xs[1:]):
		for (j, yj) in enumerate(ys[1:]):
			brd[2 * i + 1][2 * j + 1] = (yj - ys[j]) * (xi - xs[i])
	sx = bisect.bisect_left(xs, 0)
	sy = bisect.bisect_left(ys, 0)
	if sx == 0 or sy == 0 or sx == lx or (sy == ly):
		print('INF')
		exit()
	q = []
	q.append((sx * 2 - 1, sy * 2 - 1))
	ans = brd[sx * 2 - 1][sy * 2 - 1]
	brd[sx * 2 - 1][sy * 2 - 1] = 0
	while q:
		(qx, qy) = q.pop()
		for (dx, dy) in dir:
			nx = qx + dx
			ny = qy + dy
			if brd[nx][ny]:
				if nx == 0 or nx == lx * 2 - 2 or ny == 0 or (ny == ly * 2 - 2):
					print('INF')
					exit()
				nx += dx
				ny += dy
				if brd[nx][ny]:
					ans += brd[nx][ny]
					brd[nx][ny] = 0
					q.append((nx, ny))
	print(ans)
	return None
main()


import sys
sys.setrecursionlimit(10 ** 9)
input = sys.stdin.readline
from bisect import bisect_left, bisect_right
INF = 10 ** 18

def resolve():
	(n, m) = map(int, input().split())
	a = [list(map(int, input().split())) for i in range(n)]
	b = [list(map(int, input().split())) for i in range(m)]
	X = {-INF, INF}
	Y = {-INF, INF}
	for i in a:
		Y.add(i[2])
	for i in b:
		X.add(i[0])
	X = list(sorted(X))
	Y = list(sorted(Y))
	n = len(X) - 1
	m = len(Y) - 1
	wallx = [[False] * m for i in range(n)]
	wally = [[False] * m for i in range(n)]
	for (x1, x2, y1) in a:
		x1 = bisect_left(X, x1)
		y1 = bisect_left(Y, y1)
		x2 = bisect_right(X, x2) - 1
		for i in range(x1, x2):
			wally[i][y1] = True
	for (x1, y1, y2) in b:
		x1 = bisect_left(X, x1)
		y1 = bisect_left(Y, y1)
		y2 = bisect_right(Y, y2) - 1
		for i in range(y1, y2):
			wallx[x1][i] = True
	cow = [[False] * m for i in range(n)]
	cx = bisect_right(X, 0) - 1
	cy = bisect_right(Y, 0) - 1
	cow[cx][cy] = True
	q = [(cx, cy)]
	ans = 0
	while q:
		(x, y) = q.pop()
		if not x or not y:
			print('INF')
			return
		ans += (X[x + 1] - X[x]) * (Y[y + 1] - Y[y])
		if x and (not wallx[x][y]) and (not cow[x - 1][y]):
			cow[x - 1][y] = True
			q.append((x - 1, y))
		if y and (not wally[x][y]) and (not cow[x][y - 1]):
			cow[x][y - 1] = True
			q.append((x, y - 1))
		if x + 1 < n and (not wallx[x + 1][y]) and (not cow[x + 1][y]):
			cow[x + 1][y] = True
			q.append((x + 1, y))
		if y + 1 < m and (not wally[x][y + 1]) and (not cow[x][y + 1]):
			cow[x][y + 1] = True
			q.append((x, y + 1))
	print(ans)
resolve()


import sys
int1 = lambda x: int(x) - 1
p2D = lambda x: print(*x, sep='\n')

def II():
	return int(sys.stdin.readline())

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

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

def LLI(rows_number):
	return [LI() for _ in range(rows_number)]

def SI():
	return sys.stdin.readline()[:-1]

def main():
	(n, m) = MI()
	xx = set([0])
	yy = set([0])
	vl = []
	hl = []
	for _ in range(n):
		(a, b, c) = MI()
		xx.add(a)
		xx.add(b)
		yy.add(c)
		vl.append((a, b, c))
	for _ in range(m):
		(a, b, c) = MI()
		xx.add(a)
		yy.add(b)
		yy.add(c)
		hl.append((b, c, a))
	dex = list(sorted(xx))
	dey = list(sorted(yy))
	cox = {x: i for (i, x) in enumerate(dex)}
	coy = {x: i for (i, x) in enumerate(dey)}
	h = len(dex)
	w = len(dey)
	vlt = [[1] * w for _ in range(h)]
	for (x0, x1, y) in vl:
		j = coy[y]
		for i in range(cox[x0], cox[x1]):
			vlt[i][j] = 0
	hlt = [[1] * w for _ in range(h)]
	for (y0, y1, x) in hl:
		i = cox[x]
		for j in range(coy[y0], coy[y1]):
			hlt[i][j] = 0
	tt = [[False] * w for _ in range(h)]

	def inf():
		print('INF')
		exit()

	def move(ni, nj):
		if tt[ni][nj]:
			return
		tt[ni][nj] = True
		stack.append((ni, nj))
	(si, sj) = (cox[0], coy[0])
	if si == h - 1 or sj == w - 1:
		inf()
	stack = [(si, sj)]
	tt[si][sj] = True
	while stack:
		(i, j) = stack.pop()
		(ni, nj) = (i, j - 1)
		if vlt[i][j]:
			if nj == -1:
				inf()
			move(ni, nj)
		(ni, nj) = (i, j + 1)
		if vlt[ni][nj]:
			if nj == w - 1:
				inf()
			move(ni, nj)
		(ni, nj) = (i - 1, j)
		if hlt[i][j]:
			if ni == -1:
				inf()
			move(ni, nj)
		(ni, nj) = (i + 1, j)
		if hlt[ni][nj]:
			if ni == h - 1:
				inf()
			move(ni, nj)
	ans = 0
	for i in range(h - 1):
		for j in range(w - 1):
			if tt[i][j]:
				ans += (dex[i + 1] - dex[i]) * (dey[j + 1] - dey[j])
	print(ans)
main()


I = lambda : [int(i) for i in input().split()]
F = 1 << 65
r = range
(n, m) = I()
X = set([0, F, -F])
Y = set(X)
R = [((-F, F), F), ((-F, F), -F)]
H = [(F, (-F, F)), (-F, (-F, F))]
for i in r(n):
	(a, b, c) = I()
	R.append(((a, b), c))
	Y.add(c)
	X.add(a)
	X.add(b)
for i in r(m):
	(a, b, c) = I()
	H.append((a, (b, c)))
	X.add(a)
	Y.add(b)
	Y.add(c)
xdc = dict(enumerate(sorted(X)))
nx = len(xdc)
ydc = dict(enumerate(sorted(Y)))
ny = len(ydc)
h = dict(zip(xdc.values(), xdc.keys()))
w = dict(zip(ydc.values(), ydc.keys()))
V = [[0] * (nx + 1 + 1) for i in r(ny + 1 + 1)]
U = [i[:] for i in V]
for ((a, b), c) in R:
	U[w[c]][h[a]] += 1
	U[w[c]][h[b]] += -1
for i in r(ny + 1):
	for j in r(nx):
		U[i][j + 1] += U[i][j]
for (d, (e, f)) in H:
	V[w[e]][h[d]] += 1
	V[w[f]][h[d]] += -1
for j in r(nx + 1):
	for i in r(ny):
		V[i + 1][j] += V[i][j]
v = [[0] * (nx + 1) for i in r(ny + 1)]
q = [(h[0], w[0])]
v[w[0]][h[0]] = 1
a = 0
while q:
	(cx, cy) = q.pop()
	a += (xdc[cx] - xdc[cx + 1]) * (ydc[cy] - ydc[cy + 1])
	for (dx, dy) in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
		k = 0
		nbx = cx + dx
		nby = cy + dy
		if (0 <= nbx < nx) * (0 <= nby < ny) * v[nby][nbx] == 0:
			k = U[-~dy // 2 + cy][cx] == 0 if dy != 0 else V[cy][-~dx // 2 + cx] == 0
		if k:
			q.append((nbx, nby))
			v[nby][nbx] = 1
if a >= F:
	a = 'INF'
print(a)


import sys
input = sys.stdin.readline

class UnionFind:

	def __init__(self, n):
		self.par = [-1] * n

	def root(self, x):
		if self.par[x] < 0:
			return x
		else:
			self.par[x] = self.root(self.par[x])
			return self.par[x]

	def unite(self, x, y):
		(x, y) = (self.root(x), self.root(y))
		if x != y:
			if self.par[x] > self.par[y]:
				(x, y) = (y, x)
			self.par[x] += self.par[y]
			self.par[y] = x

	def same(self, x, y):
		return self.root(x) == self.root(y)

	def size(self, x):
		return -self.par[self.root(x)]

def compress_coordinate(x: list, key=None, reverse=False):
	zipped = {}
	unzipped = {}
	for (i, xi) in enumerate(sorted(set(x), key=key, reverse=reverse)):
		zipped[xi] = i
		unzipped[i] = xi
	return (zipped, unzipped)
(n, m) = map(int, input().split())
line_v = [tuple(map(int, input().split())) for _ in range(n)]
line_h = [tuple(map(int, input().split())) for _ in range(m)]
INF = 10 ** 9 + 10
x_list = [-INF, 0, INF]
y_list = [-INF, 0, INF]
for (x1, x2, y) in line_v:
	x_list.append(x1)
	x_list.append(x2)
	y_list.append(y)
for (x, y1, y2) in line_h:
	x_list.append(x)
	y_list.append(y1)
	y_list.append(y2)
(x_zipped, x_unzipped) = compress_coordinate(x_list)
(y_zipped, y_unzipped) = compress_coordinate(y_list)
nx = len(x_zipped)
ny = len(y_zipped)
v_ng = [[0] * (ny + 1) for _ in range(nx + 1)]
h_ng = [[0] * (ny + 1) for _ in range(nx + 1)]
for (x1, x2, y) in line_v:
	x1 = x_zipped[x1]
	x2 = x_zipped[x2]
	y = y_zipped[y]
	v_ng[x1][y] += 1
	v_ng[x2][y] -= 1
for (x, y1, y2) in line_h:
	x = x_zipped[x]
	y1 = y_zipped[y1]
	y2 = y_zipped[y2]
	h_ng[x][y1] += 1
	h_ng[x][y2] -= 1
for x in range(nx):
	for y in range(ny):
		v_ng[x + 1][y] += v_ng[x][y]
		h_ng[x][y + 1] += h_ng[x][y]
uf = UnionFind(nx * ny)
for x in range(nx):
	for y in range(ny):
		c0 = x * ny + y
		if y + 1 < ny and v_ng[x][y + 1] == 0:
			c1 = x * ny + (y + 1)
			uf.unite(c0, c1)
		if x + 1 < nx and h_ng[x + 1][y] == 0:
			c2 = (x + 1) * ny + y
			uf.unite(c0, c2)
c_start = x_zipped[0] * ny + y_zipped[0]
if uf.same(c_start, 0):
	ans = 'INF'
else:
	ans = 0
	for x in range(nx):
		for y in range(ny):
			if uf.same(c_start, x * ny + y):
				ans += (x_unzipped[x + 1] - x_unzipped[x]) * (y_unzipped[y + 1] - y_unzipped[y])
print(ans)


import sys
from itertools import accumulate
input = sys.stdin.buffer.readline
(N, M) = map(int, input().split())
abcs = [tuple(map(int, input().split())) for _ in range(N)]
defs = [tuple(map(int, input().split())) for _ in range(M)]
xs = set([-10 ** 9 - 2, 0, 10 ** 9 + 2])
ys = set([-10 ** 9 - 2, 0, 10 ** 9 + 2])
for (a, b, c) in abcs:
	xs.add(a)
	xs.add(b)
	ys.add(c)
for (d, e, f) in defs:
	xs.add(d)
	ys.add(e)
	ys.add(f)
scatter_x = sorted(xs)
scatter_y = sorted(ys)
gather_x = {e: i for (i, e) in enumerate(scatter_x)}
gather_y = {e: i for (i, e) in enumerate(scatter_y)}
x_size = 2 * len(scatter_x)
y_size = 2 * len(scatter_y)
field = [[0] * y_size for _ in range(x_size)]
for (a, b, c) in abcs:
	field[2 * gather_x[a]][2 * gather_y[c]] += 1
	field[2 * gather_x[b] + 1][2 * gather_y[c]] -= 1
	field[2 * gather_x[a]][2 * gather_y[c] + 1] -= 1
	field[2 * gather_x[b] + 1][2 * gather_y[c] + 1] += 1
for (d, e, f) in defs:
	field[2 * gather_x[d]][2 * gather_y[e]] += 1
	field[2 * gather_x[d]][2 * gather_y[f] + 1] -= 1
	field[2 * gather_x[d] + 1][2 * gather_y[e]] -= 1
	field[2 * gather_x[d] + 1][2 * gather_y[f] + 1] += 1
for x in range(x_size):
	field[x] = list(accumulate(field[x]))
for x in range(x_size - 1):
	for y in range(y_size):
		field[x + 1][y] += field[x][y]
area = 0
sx = gather_x[0] * 2 + 1
sy = gather_y[0] * 2 + 1
field[sx][sy] = 1
stack_x = [sx]
stack_y = [sy]
while stack_x:
	x = stack_x.pop()
	y = stack_y.pop()
	if x == 1 or y == 1 or x == x_size - 1 or (y == y_size - 1):
		print('INF')
		exit()
	if field[x + 1][y] == field[x + 2][y] == 0:
		stack_x.append(x + 2)
		stack_y.append(y)
		field[x + 2][y] = 1
	if field[x][y + 1] == field[x][y + 2] == 0:
		stack_x.append(x)
		stack_y.append(y + 2)
		field[x][y + 2] = 1
	if field[x - 1][y] == field[x - 2][y] == 0:
		stack_x.append(x - 2)
		stack_y.append(y)
		field[x - 2][y] = 1
	if field[x][y - 1] == field[x][y - 2] == 0:
		stack_x.append(x)
		stack_y.append(y - 2)
		field[x][y - 2] = 1
	delta_x = scatter_x[x // 2 + 1] - scatter_x[x // 2]
	delta_y = scatter_y[y // 2 + 1] - scatter_y[y // 2]
	area += delta_x * delta_y
print(area)


(n, m, *l) = map(int, open(0).read().split())
l = iter(l)
l = list(zip(l, l, l))
l1 = l[:n]
l2 = l[-m:]
V = set([float('inf'), -float('inf')])
H = set([float('inf'), -float('inf')])
for (a, b, c) in l1:
	V.add(c)
	H.add(a)
	H.add(b)
for (c, a, b) in l2:
	H.add(c)
	V.add(a)
	V.add(b)
V = sorted(list(V))
H = sorted(list(H))
Vdic = {}
Hdic = {}
for (i, v) in enumerate(V):
	Vdic[v] = i
for (i, h) in enumerate(H):
	Hdic[h] = i
checkv = [[0] * 3001 for i in range(3001)]
checkh = [[0] * 3001 for i in range(3001)]
check = [[0] * 3001 for i in range(3001)]
for (a, b, c) in l1:
	c = Vdic[c]
	for i in range(Hdic[a], Hdic[b]):
		checkh[c][i] = 1
for (c, a, b) in l2:
	c = Hdic[c]
	for i in range(Vdic[a], Vdic[b]):
		checkv[i][c] = 1
from bisect import bisect_left
pv = bisect_left(V, 0) - 1
ph = bisect_left(H, 0) - 1
ans = 0
stack = [(pv, ph)]
check[pv][ph] = 1
while stack:
	(v, h) = stack.pop()
	ans += (V[v + 1] - V[v]) * (H[h + 1] - H[h])
	if h != 0 and checkv[v][h] == 0 and (check[v][h - 1] == 0):
		stack.append((v, h - 1))
		check[v][h - 1] = 1
	if h != len(H) - 2 and checkv[v][h + 1] == 0 and (check[v][h + 1] == 0):
		stack.append((v, h + 1))
		check[v][h + 1] = 1
	if v != 0 and checkh[v][h] == 0 and (check[v - 1][h] == 0):
		stack.append((v - 1, h))
		check[v - 1][h] = 1
	if v != len(V) - 2 and checkh[v + 1][h] == 0 and (check[v + 1][h] == 0):
		stack.append((v + 1, h))
		check[v + 1][h] = 1
print('INF' if ans == float('inf') else ans)


import sys
input = sys.stdin.readline
from collections import deque
INF = 10 ** 20
(n, m) = map(int, input().split())
xseen = set()
xseen.add(INF)
xseen.add(-INF)
yseen = set()
yseen.add(INF)
yseen.add(-INF)
a_b_c = []
for _ in range(n):
	(a, b, c) = map(int, input().split())
	xseen.add(a)
	xseen.add(b)
	yseen.add(c)
	a_b_c.append((a, b, c))
d_e_f = []
for _ in range(m):
	(d, e, f) = map(int, input().split())
	xseen.add(d)
	yseen.add(e)
	yseen.add(f)
	d_e_f.append((d, e, f))
xlen = len(xseen) * 2 - 1
ylen = len(yseen) * 2 - 1
xseen = sorted(list(xseen))
xcomp = {val: i for (i, val) in enumerate(xseen)}
yseen = sorted(list(yseen))
ycomp = {val: i for (i, val) in enumerate(yseen)}
field = [[0] * ylen for _ in range(xlen)]
x_range = [0] * xlen
y_range = [0] * ylen
x_range[0] = x_range[-1] = INF
y_range[0] = y_range[-1] = INF
for (i, (x1, x2)) in enumerate(zip(xseen, xseen[1:])):
	x_range[i * 2 + 1] = x2 - x1
	if x1 <= 0 <= x2:
		sx = i * 2 + 1
for (i, (y1, y2)) in enumerate(zip(yseen, yseen[1:])):
	y_range[i * 2 + 1] = y2 - y1
	if y1 <= 0 <= y2:
		sy = i * 2 + 1
for (a, b, c) in a_b_c:
	y = ycomp[c] * 2
	for x in range(xcomp[a] * 2 + 1, xcomp[b] * 2 + 1, 2):
		field[x][y] = 1
for (d, e, f) in d_e_f:
	x = xcomp[d] * 2
	for y in range(ycomp[e] * 2 + 1, ycomp[f] * 2 + 1, 2):
		field[x][y] = 1
diff = ((0, 1), (1, 0), (-1, 0), (0, -1))
ans = 0
dq = deque([(sx, sy)])
field[sx][sy] = 1
ans += x_range[sx] * y_range[sy]
while dq:
	(x, y) = dq.popleft()
	for (dx, dy) in diff:
		(nx, ny) = (dx + x, dy + y)
		if field[nx][ny]:
			continue
		nx += dx
		ny += dy
		if field[nx][ny]:
			continue
		field[nx][ny] = 1
		dq.append((nx, ny))
		ans += x_range[nx] * y_range[ny]
		if ans >= INF:
			print('INF')
			exit()
print(ans)


import sys
from collections import defaultdict
input = sys.stdin.readline
(n, m) = map(int, input().split())
xx = set([0])
yy = set([0])
aa = []
bb = []
cc = []
dd = []
ee = []
ff = []
for _ in range(n):
	(a, b, c) = map(int, input().split())
	xx.add(a)
	xx.add(b)
	yy.add(c)
	aa.append(a)
	bb.append(b)
	cc.append(c)
for _ in range(m):
	(d, e, f) = map(int, input().split())
	xx.add(d)
	yy.add(e)
	yy.add(f)
	dd.append(d)
	ee.append(e)
	ff.append(f)
xx = sorted(list(xx))
yy = sorted(list(yy))
xp = defaultdict(int)
yp = defaultdict(int)
for (i, v) in enumerate(xx):
	xp[v] = i
for (i, v) in enumerate(yy):
	yp[v] = i
h = len(xx) - 1
w = len(yy) - 1
lx = [[0 for _ in range(w + 1)] for _ in range(h + 1)]
ly = [[0 for _ in range(w + 1)] for _ in range(h + 1)]
for i in range(n):
	(a, b, c) = (aa[i], bb[i], cc[i])
	for x in range(xp[a], xp[b]):
		lx[x][yp[c]] = 1
for i in range(m):
	(d, e, f) = (dd[i], ee[i], ff[i])
	for y in range(yp[e], yp[f]):
		ly[xp[d]][y] = 1
visited = [[False for _ in range(w)] for _ in range(h)]
(sx, sy) = (min(xp[0], h - 1), min(yp[0], w - 1))
visited[sx][sy] = True
q = [(sx, sy)]
ans = 0
while q:
	(x, y) = q.pop()
	ans += (xx[x + 1] - xx[x]) * (yy[y + 1] - yy[y])
	if ly[x][y] == 0:
		if x == 0:
			print('INF')
			exit()
		if not visited[x - 1][y]:
			visited[x - 1][y] = True
			q.append((x - 1, y))
	if lx[x][y] == 0:
		if y == 0:
			print('INF')
			exit()
		if not visited[x][y - 1]:
			visited[x][y - 1] = True
			q.append((x, y - 1))
	if ly[x + 1][y] == 0:
		if x == h - 1:
			print('INF')
			exit()
		if not visited[x + 1][y]:
			visited[x + 1][y] = True
			q.append((x + 1, y))
	if lx[x][y + 1] == 0:
		if y == w - 1:
			print('INF')
			exit()
		if not visited[x][y + 1]:
			visited[x][y + 1] = True
			q.append((x, y + 1))
print(ans)


mod = 1000000007
eps = 10 ** (-9)

def main():
	import sys
	from collections import deque
	input = sys.stdin.buffer.readline

	def fin():
		print('INF')
		exit()
	(N, M) = map(int, input().split())
	X = set()
	X.add(-10 ** 9 - 1)
	X.add(0)
	X.add(10 ** 9 + 1)
	Y = set()
	Y.add(-10 ** 9 - 1)
	Y.add(0)
	Y.add(10 ** 9 + 1)
	ABC = []
	DEF = []
	for _ in range(N):
		(a, b, c) = map(int, input().split())
		X.add(a)
		X.add(b)
		Y.add(c)
		ABC.append((a, b, c))
	for _ in range(M):
		(d, e, f) = map(int, input().split())
		X.add(d)
		Y.add(e)
		Y.add(f)
		DEF.append((d, e, f))
	X = sorted(list(X))
	Y = sorted(list(Y))
	x2i = {x: i for (i, x) in enumerate(X)}
	y2j = {y: j for (j, y) in enumerate(Y)}
	LX = len(X)
	LY = len(Y)
	ABCwall = [set() for _ in range(LY)]
	for (a, b, c) in ABC:
		i0 = x2i[a]
		i1 = x2i[b]
		j = y2j[c]
		for i in range(i0, i1):
			ABCwall[j].add(i)
	DEFwall = [set() for _ in range(LX)]
	for (d, e, f) in DEF:
		i = x2i[d]
		j0 = y2j[e]
		j1 = y2j[f]
		for j in range(j0, j1):
			DEFwall[i].add(j)
	ii = x2i[0]
	jj = y2j[0]
	que = deque()
	que.append((ii, jj))
	seen = [[0] * (LY - 1) for _ in range(LX - 1)]
	seen[ii][jj] = 1
	ans = 0
	while que:
		(i, j) = que.popleft()
		ans += (X[i + 1] - X[i]) * (Y[j + 1] - Y[j])
		if j not in DEFwall[i + 1]:
			if i == LX - 2:
				fin()
			if not seen[i + 1][j]:
				que.append((i + 1, j))
				seen[i + 1][j] = 1
		if j not in DEFwall[i]:
			if i == 1:
				fin()
			if not seen[i - 1][j]:
				que.append((i - 1, j))
				seen[i - 1][j] = 1
		if i not in ABCwall[j + 1]:
			if j == LY - 2:
				fin()
			if not seen[i][j + 1]:
				que.append((i, j + 1))
				seen[i][j + 1] = 1
		if i not in ABCwall[j]:
			if j == 1:
				fin()
			if not seen[i][j - 1]:
				que.append((i, j - 1))
				seen[i][j - 1] = 1
	print(ans)
main()


import bisect
import sys
lower_bound = bisect.bisect_left
upper_bound = bisect.bisect_right
INF = 1073741823
(n, m) = map(int, input().split())
a = [list(map(int, input().split())) for i in range(n)]
b = [list(map(int, input().split())) for i in range(m)]
X = {-INF, INF}
Y = {-INF, INF}
for i in a:
	Y.add(i[2])
for i in b:
	X.add(i[0])
X = list(sorted(X))
Y = list(sorted(Y))
n = len(X) - 1
m = len(Y) - 1
wallx = [[False] * m for i in range(n)]
wally = [[False] * m for i in range(n)]
for (x1, x2, y1) in a:
	x1 = lower_bound(X, x1)
	y1 = lower_bound(Y, y1)
	x2 = upper_bound(X, x2) - 1
	for i in range(x1, x2):
		wally[i][y1] = True
for (x1, y1, y2) in b:
	x1 = lower_bound(X, x1)
	y1 = lower_bound(Y, y1)
	y2 = upper_bound(Y, y2) - 1
	for i in range(y1, y2):
		wallx[x1][i] = True
cow = [[False] * m for i in range(n)]
cx = upper_bound(X, 0) - 1
cy = upper_bound(Y, 0) - 1
cow[cx][cy] = True
q = [(cx, cy)]
ans = 0
while q:
	(x, y) = q.pop()
	if not x or not y:
		print('INF')
		sys.exit()
	ans += (X[x + 1] - X[x]) * (Y[y + 1] - Y[y])
	if x and (not wallx[x][y]) and (not cow[x - 1][y]):
		cow[x - 1][y] = True
		q.append((x - 1, y))
	if y and (not wally[x][y]) and (not cow[x][y - 1]):
		cow[x][y - 1] = True
		q.append((x, y - 1))
	if x + 1 < n and (not wallx[x + 1][y]) and (not cow[x + 1][y]):
		cow[x + 1][y] = True
		q.append((x + 1, y))
	if y + 1 < m and (not wally[x][y + 1]) and (not cow[x][y + 1]):
		cow[x][y + 1] = True
		q.append((x, y + 1))
print(ans)


import bisect
import sys
readline = sys.stdin.readline
(N, M) = map(int, readline().split())
INF = 10 ** 9 + 1
s_X = set([-INF, 0, INF])
s_Y = set([-INF, 0, INF])

def compress(s):
	ls = list(s)
	ls.sort()
	return {e: i for (i, e) in enumerate(ls)}
ABC = []
for i in range(N):
	(A, B, C) = map(int, readline().split())
	ABC.append((A, B, C))
	s_Y.add(C)
DEF = []
for i in range(M):
	(D, E, F) = map(int, readline().split())
	DEF.append((D, E, F))
	s_X.add(D)
mapX = compress(s_X)
mapY = compress(s_Y)
l_X = list(mapX.keys())
l_Y = list(mapY.keys())
maxX = len(mapX) * 2
maxY = len(mapY) * 2
W = [[0] * maxY for _ in range(maxX)]
for (A, B, C) in ABC:
	A = mapX[l_X[bisect.bisect_left(l_X, A)]]
	B = mapX[l_X[bisect.bisect_right(l_X, B) - 1]]
	C = mapY[C]
	A *= 2
	B *= 2
	C *= 2
	for j in range(A, B + 1):
		W[j][C] = 1
for (D, E, F) in DEF:
	D = mapX[D]
	E = mapY[l_Y[bisect.bisect_left(l_Y, E)]]
	F = mapY[l_Y[bisect.bisect_right(l_Y, F) - 1]]
	D *= 2
	E *= 2
	F *= 2
	for j in range(E, F + 1):
		W[D][j] = 1
q = []
q.append((mapX[0] * 2, mapY[0] * 2))
W[mapX[0] * 2][mapY[0] * 2] = 1
ans = 0
b_ans = True
while q:
	(x, y) = q.pop()
	if x == maxX or x == 0 or y == maxY or (y == 0):
		b_ans = False
		break
	for (vx, vy) in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
		nx = x + vx
		ny = y + vy
		if W[nx][ny] == 0:
			if nx % 2 == 1 and ny % 2 == 1:
				ex = l_X[(nx + 1) // 2] - l_X[(nx - 1) // 2]
				ey = l_Y[(ny + 1) // 2] - l_Y[(ny - 1) // 2]
				ans += ex * ey
			q.append((nx, ny))
			W[nx][ny] = 1
if b_ans == True:
	print(ans)
else:
	print('INF')


(N, M) = map(int, input().split())
(A, B, X, Y) = ([], [], {-10 ** 9 - 1, 0, 10 ** 9 + 1}, {-10 ** 9 - 1, 0, 10 ** 9 + 1})
for _ in range(N):
	(a, b, c) = map(int, input().split())
	A.append((a, b, c))
	X.add(a)
	X.add(b)
	Y.add(c)
for _ in range(M):
	(d, e, f) = map(int, input().split())
	B.append((d, e, f))
	X.add(d)
	Y.add(e)
	Y.add(f)
X = sorted(list(X))
Y = sorted(list(Y))
S = {a: i for (i, a) in enumerate(X)}
T = {a: i for (i, a) in enumerate(Y)}
H = len(X)
W = len(Y)
Z1 = [[0] * W for _ in range(H)]
Z2 = [[0] * W for _ in range(H)]
for (a, b, c) in A:
	(a, b, c) = (S[a], S[b], T[c])
	for i in range(a, b):
		Z1[i][c] = 1
for (d, e, f) in B:
	(d, e, f) = (S[d], T[e], T[f])
	for j in range(e, f):
		Z2[d][j] = 1
s = S[0] * W + T[0]
from collections import deque

def BFS(i0=0):
	Q = deque([i0])
	D = [-1] * (H * W)
	D[i0] = 0
	ans = (X[S[0] + 1] - X[S[0]]) * (Y[T[0] + 1] - Y[T[0]])
	while Q:
		x = Q.popleft()
		(i, j) = (x // W, x % W)
		dd = []
		if Z1[i][j] == 0:
			dd.append((0, -1))
		if Z1[i][j + 1] == 0:
			dd.append((0, 1))
		if Z2[i][j] == 0:
			dd.append((-1, 0))
		if Z2[i + 1][j] == 0:
			dd.append((1, 0))
		for (di, dj) in dd:
			(ni, nj) = (i + di, j + dj)
			if not (0 < ni < H - 1 and 0 < nj < W - 1):
				print('INF')
				exit()
			y = ni * W + nj
			if D[y] == -1:
				D[y] = D[x] + 1
				ans += (X[ni + 1] - X[ni]) * (Y[nj + 1] - Y[nj])
				Q.append(y)
	return ans
bfs = BFS(s)
print(bfs)