// clang-format off
	#define BADSEED random_device{}()
	#include <vector>
	#include <array>
	#include <queue>
	#include <iostream>
	#include <algorithm>
	using namespace std;
	using ll = long long;
	using uint = unsigned int;
	ostream &operator<<(ostream &os, int8_t c) { return os << short(c); }
	istream &operator>>(istream &is, int8_t &c) { short x; is >> x; c = x; return is; }
	#define TM_(...) template <class __VA_ARGS__>
	namespace narut {
	TM_(T) using TupSz = tuple_size<decay_t<T>>;
	TM_(T) constexpr auto spc(T const &t, int) -> decltype((cout << t), 'a') { return ' '; }
	constexpr auto spc(string const &s, int) { return '\n'; }
	TM_(T) constexpr auto spc(T const &t, char) { return '\n'; }
	struct IO {
		TM_(T) static auto out_(ostream &os, T const &t, int) -> decltype(void(os << t)) { os << t; }
		TM_(T, class OS) static auto out_(OS &os, T const &t, int) -> decltype(void(begin(t))) {
			auto it = begin(t), e = end(t);
			if (it != e) out_(os, *it++, 0);
			for (; it != e; out_(os, *it++, 0)) os << spc(*it, 0);
		}
		TM_(T, size_t... Is) static void out_tup(ostream &os, T const &t, index_sequence<Is...>) { (void)initializer_list<int>{0, ((Is == 0) ? 0 : ((os << ' '), 0), (os << get<Is>(t)), 0)...}; }
		TM_(T) static decltype(void(TupSz<T>{})) out_(ostream &os, T const &t, char) { out_tup(os, t, make_index_sequence<TupSz<T>::value>{}); }
		TM_(Sep, class F, class... Ts) static ostream &print(ostream &os, Sep sep, F const &f, Ts const &... ts) { return void(initializer_list<int>{(out_(os, f, 0), 0), (out_(os << sep, ts, 0), 0)...}), os; }
		TM_(T) static auto in_(istream &is, T &t, int) -> decltype(void(is >> t)) { is >> t; }
		TM_(T, class IS) static auto in_(IS &is, T &t, int) -> decltype(void(begin(t))) { for (auto &x : t) in_(is, x, 0); }
		TM_(T, size_t... Is) static void in_tup(istream &is, T &t, index_sequence<Is...>) { (void)initializer_list<int>{0, (in_(is, get<Is>(t), 0), 0)...}; }
		TM_(T) static decltype(void(TupSz<T>{})) in_(istream &is, T &t, char) { in_tup(is, t, make_index_sequence<TupSz<T>::value>{}); }
	};
	} // namespace narut
	#define Cout(...) narut::IO::print(cout, ' ', __VA_ARGS__) << '\n'
	#ifdef NARUT_LOCAL
	#define Debug(...) narut::IO::print(cerr << "\033[0;31m", ", ", __VA_ARGS__) << "\033[0m\n"
	#else
	#define Debug(...) 0
	#endif
	[[maybe_unused]] struct Cin {
		template <class T> Cin const &operator>>(T &t) const { return narut::IO::in_(cin, t, 0), *this; }
		template <class T> operator T() const { T t; return *this >> t, t;  }
	} Cin;
	TM_(T) auto operator%(T &t, size_t n) -> decltype(t.resize(n), t)& { return t.resize(n), t; }
	#define FOR(i, j, n) for (int i = int(j); i < int(n); ++i)
	#define ROF(i, j, n) for (int i = int(n) - 1; i >= int(j); --i)

// clang-format on


int n, m;

int inf = 0x3f3f3f3f;

vector<int> X = {-inf, 0, inf};
vector<int> Y = X;

auto MakeLookup(vector<pair<int, int>> const &v) {
	return
		[&v](auto x) { return lower_bound(v.begin(), v.end(), pair<int, int>(x, x)) - v.begin(); };
}

auto Main() {
	cin >> n >> m;
	vector<array<int, 3>> ns(n), we(m);
	Cin >> ns >> we;

	X.reserve(3000);
	Y.reserve(3000);

	for (auto [a, b, c] : ns) {
		X.push_back(a);
		X.push_back(b);
		Y.push_back(c);
	}
	for (auto [d, e, f] : we) {
		X.push_back(d);
		Y.push_back(e);
		Y.push_back(f);
	}

	sort(begin(X), end(X));
	X.erase(unique(begin(X), end(X)), end(X));

	sort(begin(Y), end(Y));
	Y.erase(unique(begin(Y), end(Y)), end(Y));

	vector<pair<int, int>> xlimits;
	vector<pair<int, int>> ylimits;

	xlimits.reserve(3000);
	ylimits.reserve(3000);

	FOR(i, 1, X.size()) {
		xlimits.emplace_back(X[i - 1], X[i]);
		xlimits.emplace_back(X[i], X[i]);
	}
	FOR(i, 1, Y.size()) {
		ylimits.emplace_back(Y[i - 1], Y[i]);
		ylimits.emplace_back(Y[i], Y[i]);
	}

	const auto lookX = MakeLookup(xlimits);
	const auto lookY = MakeLookup(ylimits);

	vector<vector<int8_t>> blocks(xlimits.size(), vector<int8_t>(ylimits.size()));

	for (auto [a, b, c] : ns) {
		auto ia = lookX(a);
		auto ib = lookX(b);
		auto k = lookY(c);
		for (int j = ia; j <= ib; j++) blocks[j][k] = 1;
	}
	for (auto [d, e, f] : we) {
		auto k = lookX(d);
		auto ia = lookY(e);
		auto ib = lookY(f);
		for (int j = ia; j <= ib; j++) blocks[k][j] = 1;
	}

	int s_x = lookX(0), s_y = lookY(0);
	queue<pair<int, int>> q;
	q.emplace(s_x, s_y);
	ll area = 0;
	while(!q.empty()) {
		auto [u, v] = q.front();
		q.pop();
		if (blocks[u][v]==1) continue;
		blocks[u][v]=1;
		
		const auto& xu = xlimits[u];
		const auto& yv = ylimits[v];

		for (int z : {xu.first, xu.second, yv.first, yv.second}) {
			if (abs(z)==inf) throw 1;
		}
		auto d_x = xu.second - xu.first;
		auto d_y = yv.second - yv.first;
		area += ll(d_x)*d_y;

		q.emplace(u-1,v);
		q.emplace(u+1,v);
		q.emplace(u,v-1);
		q.emplace(u,v+1);
	}

	cout << area;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout << fixed << setprecision(10);
#ifdef NARUT_LOCAL
	assert(freopen("io/test.in", "r", stdin));
	cin.exceptions(cin.badbit | cin.failbit);
	cerr << fixed << setprecision(10);
#endif
	try {
		Main();
	} catch (int) {
		cout << "INF";
	}
}
