#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <iomanip>
#include <functional>
#include <bitset>
#include <limits>
#include <cstdio>
#include <cmath>
#include <cassert>
#include <random>

#ifdef DEBUG
#include "library/Utility/debug.cpp"
#else
#define debug(...)
#endif

#define rep(i,n) for(int i=0;i<(n);++i)
#define EL '\n'
#define print(i) std::cout << (i) << '\n'
#define all(v) (v).begin(), (v).end()
using lnt = long long;
constexpr lnt INF = 2e18;
/*-*/

struct UnionFind
{
  int n;
  std::vector<int> par,size;
  UnionFind(int sz) : n(sz), par(sz,0), size(sz,1) {
    std::iota(par.begin(),par.end(),0);
  }
  int find(int x) {
    if(par[x]==x) return x;
    return par[x] = find(par[x]);
  }
  void unite(int x, int y) {
    x=find(x);y=find(y);
    if(x==y) return;
    if(size[x]<size[y]) std::swap(x,y);
    size[x]+=size[y];
    par[y]=x;
  }
};


template <typename T = lnt>
struct CoordinateCompression
{
	// add with .r.emplace_back(), T->int with [], int-> T with .r[]
	std::vector<T> r;
	CoordinateCompression() {}
	void build(bool sorted=false) {
		if(!sorted) std::sort(r.begin(),r.end());
		r.erase(std::unique(r.begin(),r.end()),r.end());
	}
	int operator[](const T& k) const {
		return (int)(std::lower_bound(r.begin(),r.end(),k)-r.begin());
	}
};

struct P
{
	lnt a,b,c;
	P(lnt a, lnt b, lnt c) : a(a),b(b),c(c) {}
};

int main() {
	lnt n,m;
	std::cin >> n >> m;
	std::vector<std::vector<P> > edges(2);
	std::vector<CoordinateCompression<lnt>> C(2);
	rep(i,n) {
		lnt a,b,c;
		std::cin >> a >> b >> c;
		edges[0].emplace_back(a,b,c);
		C[0].r.emplace_back(a);
		C[0].r.emplace_back(b);
		C[1].r.emplace_back(c);
	}
	rep(i,m) {
		lnt a,b,c;
		std::cin >> c >> a >> b;
		edges[1].emplace_back(a,b,c);
		C[1].r.emplace_back(a);
		C[1].r.emplace_back(b);
		C[0].r.emplace_back(c);
	}
	C[0].r.emplace_back(0);
	C[1].r.emplace_back(0);
	rep(i,2) C[i].build();
	lnt N=C[0].r.size()+1;
	lnt M=C[1].r.size()+1;
	std::vector<std::vector<lnt> > bN(N,std::vector<lnt>(M,0));
	std::vector<std::vector<lnt> > bM(M,std::vector<lnt>(N,0));
	for(auto e:edges[0]) {
		bM[C[1][e.c]][C[0][e.a]]++;
		bM[C[1][e.c]][C[0][e.b]]--;
	}
	for(auto e:edges[1]) {
		bN[C[0][e.c]][C[1][e.a]]++;
		bN[C[0][e.c]][C[1][e.b]]--;
	}
	rep(i,N-1) {
		rep(j,M-1) {
			bN[i][j+1]+=bN[i][j];
			bM[j][i+1]+=bM[j][i];
		}
	}
	auto enc = [&](int i, int j) -> lnt {
		return i*M+j;
	};
	UnionFind uf(N*M);
	rep(i,N) {
		rep(j,M) {
			if(j!=M-1&&(i==0||i==N-1||bM[j][i-1]==0)) {
				uf.unite(enc(i,j),enc(i,j+1));
			}
			if(i!=N-1&&(j==0||j==M-1||bN[i][j-1]==0)) {
				uf.unite(enc(i,j),enc(i+1,j));
			}
		}
	}
	lnt sx=C[0][0]+1;
	lnt sy=C[1][0]+1;
	lnt root = uf.find(enc(sx,sy));
	lnt sum=0;
	rep(i,N) {
		rep(j,M) {
			if(uf.find(enc(i,j))==root) {
				if(i==0||j==0||i==N-1||j==M-1) {
					print("INF");
					return 0;
				}
				sum+=(C[0].r[i]-C[0].r[i-1])*(C[1].r[j]-C[1].r[j-1]);
			}
		}
	}
	print(sum);
}
