#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <random>
#include <complex>
#include <assert.h>

using namespace std;
typedef long long ll;
#define endl '\n'

template<typename T>
inline bool chmin(T& x, T a) {
	if (x >= a) { x = a; return true; }
	return false;
}

template<typename T>
inline bool chmax(T& x, T a) {
	if (x <= a) { x = a; return true; }
	return false;
}

template<typename T>
class compressionClass {
public:
	compressionClass() {
		st.clear();
	}
	void add(T element) {
		st.insert(element);
	}
	void execute() {
		v.clear();
		mmap.clear();

		v.resize(st.size());
		int i = 0;
		for (auto itr = st.begin(); itr != st.end(); itr++) {
			v[i] = *itr;
			mmap.insert({ *itr, i });
			i++;
		}
		N = v.size();
	}

	int N;
	vector<T> v;
	unordered_map<T, int> mmap;

private:
	set<T> st;
};

const int UP = 1, DOWN = 2, LEFT = 4, RIGHT = 8;
class gridClass {
public:
	gridClass() {
		W = 0;
		H = 0;
		direction.clear();
		active.clear();
	}
	gridClass(int H0, int W0) {
		init(H0, W0);
	}
	void init(int H0, int W0) {
		H = H0, W = W0;
		direction.clear();
		direction.resize(H);
		active.clear();
		active.resize(H);

		for (int y = 0; y < H; y++) {
			direction[y].clear();
			direction[y].resize(W);
			active[y].clear();
			active[y].resize(W);

			for (int x = 0; x < W; x++) {
				direction[y][x] = 0;
				if (y > 0) { direction[y][x] += UP; }
				if (y < H - 1) { direction[y][x] += DOWN; }
				if (x > 0) { direction[y][x] += LEFT; }
				if (x < W - 1) { direction[y][x] += RIGHT; }

				active[y][x] = true;
			}
		}
	}

	void enable(int y, int x, int command = 0, bool directedFlag = false) {
		if (command == 0) {
			active[y][x] = true;
			return;
		}
		if (command & UP) {
			if (y > 0) {
				direction[y][x] |= UP;
				if (directedFlag == false) { direction[y - 1][x] |= DOWN; }
			}
		}
		if (command & DOWN) {
			if (y < H - 1) {
				direction[y][x] |= DOWN;
				if (directedFlag == false) { direction[y + 1][x] |= UP; }
			}
		}
		if (command & LEFT) {
			if (x > 0) {
				direction[y][x] |= LEFT;
				if (directedFlag == false) { direction[y][x - 1] |= RIGHT; }
			}
		}
		if (command & RIGHT) {
			if (x < W - 1) {
				direction[y][x] |= RIGHT;
				if (directedFlag == false) { direction[y][x + 1] |= LEFT; }
			}
		}
	}
	void disable(int y, int x, int command = 0, bool directedFlag = false) {
		if (command == 0) {
			active[y][x] = false;
			return;
		}
		if (command & UP) {
			if (y > 0) {
				direction[y][x] &= (15 - UP);
				if (directedFlag == false) { direction[y - 1][x] &= (15 - DOWN); }
			}
		}
		if (command & DOWN) {
			if (y < H - 1) {
				direction[y][x] &= (15 - DOWN);
				if (directedFlag == false) { direction[y + 1][x] &= (15 - UP); }
			}
		}
		if (command & LEFT) {
			if (x > 0) {
				direction[y][x] &= (15 - LEFT);
				if (directedFlag == false) { direction[y][x - 1] &= (15 - RIGHT); }
			}
		}
		if (command & RIGHT) {
			if (x < W - 1) {
				direction[y][x] &= (15 - RIGHT);
				if (directedFlag == false) { direction[y][x + 1] &= (15 - LEFT); }
			}
		}
	}

	void getBfsOrder(
		vector<pair<pair<int, int>, int>>& dest, // { { y座標(i成分), x座標(j成分) }, 親ノード番号 }
		vector<pair<int, int>> src = { { 0,0 } } // y座標(i成分)、x座標(j成分)の順
	) {
		dest.clear();

		vector<vector<int>> order(H);
		for (int i = 0; i < H; i++) {
			order[i].resize(W, -1);
		}

		queue<pair<pair<int, int>, int>> q;

		int counter = 0;

		for (int i = 0; i < src.size(); i++) {
			q.push({ src[i], -1 });
			order[src[i].first][src[i].second] = counter;
			counter++;
		}

		while (q.size() > 0) {
			dest.push_back(q.front());
			pair<int, int> p = q.front().first;
			q.pop();

			if (
				(direction[p.first][p.second] & UP) != 0 &&
				active[p.first - 1][p.second] == true &&
				order[p.first - 1][p.second] == -1
				) {
				q.push({ {p.first - 1,p.second},order[p.first][p.second] });
				order[p.first - 1][p.second] = counter; counter++;
			}
			if (
				(direction[p.first][p.second] & DOWN) != 0 &&
				active[p.first + 1][p.second] == true &&
				order[p.first + 1][p.second] == -1
				) {
				q.push({ {p.first + 1,p.second},order[p.first][p.second] });
				order[p.first + 1][p.second] = counter; counter++;
			}
			if (
				(direction[p.first][p.second] & LEFT) != 0 &&
				active[p.first][p.second - 1] == true &&
				order[p.first][p.second - 1] == -1
				) {
				q.push({ {p.first, p.second - 1}, order[p.first][p.second] });
				order[p.first][p.second - 1] = counter; counter++;
			}
			if (
				(direction[p.first][p.second] & RIGHT) != 0 &&
				active[p.first][p.second + 1] == true &&
				order[p.first][p.second + 1] == -1
				) {
				q.push({ {p.first, p.second + 1},order[p.first][p.second] });
				order[p.first][p.second + 1] = counter; counter++;
			}
		}
	}

	int H, W;

	vector<vector<int>> direction;
	vector<vector<bool>> active;
};

int main() {
	ios::sync_with_stdio(false);
	std::cin.tie(0);

	ll N, M; cin >> N >> M;
	vector<pair<pair<ll, ll>, ll>> v1(N);
	vector<pair<ll, pair<ll, ll>>> v2(M);

	compressionClass<ll> C1, C2;

	C1.add(0);
	C2.add(0);

	for (int i = 0; i < N; i++) {
		ll a, b, c; cin >> a >> b >> c;
		v1[i] = { {a, b}, c };
		C1.add(a);
		C1.add(b);
		C2.add(c);
	}
	for (int i = 0; i < M; i++) {
		ll d, e, f; cin >> d >> e >> f;
		v2[i] = { d, {e, f} };
		C1.add(d);
		C2.add(e);
		C2.add(f);
	}

	C1.execute();
	C2.execute();

	gridClass G(C2.N + 1, C1.N + 1);

	for (int i = 0; i < N; i++) {
		ll x0, x1, y;
		x0 = C1.mmap[v1[i].first.first];
		x1 = C1.mmap[v1[i].first.second];
		y = C2.mmap[v1[i].second];

		for (int x = x0; x < x1; x++) {
			G.disable(y + 1, x + 1, UP);
		}
	}

	for (int i = 0; i < M; i++) {
		ll x, y0, y1;
		x = C1.mmap[v2[i].first];
		y0 = C2.mmap[v2[i].second.first];
		y1 = C2.mmap[v2[i].second.second];

		for (int y = y0; y < y1; y++) {
			G.disable(y + 1, x + 1, LEFT);
		}
	}

	

	vector<pair<pair<int, int>, int>> dest;
	G.getBfsOrder(dest, { { C2.mmap[0] + 1, C1.mmap[0] + 1} });

	ll ans = 0;
	for (int i = 0; i < dest.size(); i++) {
		pair<int, int> p = dest[i].first;
		if (p.first == 0 || p.second == 0 || p.first == C2.N || p.second == C1.N) {
			cout << "INF" << endl;
			return 0;
		}
		ans += (C1.v[p.second] - C1.v[p.second - 1]) * (C2.v[p.first] - C2.v[p.first - 1]);
	}
	cout << ans << endl;

	return 0;
}

Measured memory_bytes: 272124