#include <bits/stdc++.h>
// #include <atcoder/all>
#define ll long long int
#define ld long double
#define yorn(f) std::cout<<((f)?"Yes":"No")<<endl;
#define YORN(f) std::cout<<((f)?"YES":"NO")<<endl;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define repi(i, n) for (ll i = 1; i < (ll)(n); i++)
#define all(x) (x).begin(), (x).end()
#define put(x) std::cout << x << endl;
#define println(x) std::cout << x << endl;
template<typename T>bool mins(T& x,const T&y){if(x>y){x=y;return true;}else return false;}
template<typename T>bool maxs(T& x,const T&y){if(x<y){x=y;return true;}else return false;}
const ll INF = 1e18;
using namespace std;
// using namespace atcoder;
void Main()
{
    ll n, M;
    cin >> n >> M;

    vector<ll> A(n), B(n), C(n);
    rep(i, n) cin >> A[i] >> B[i] >> C[i];
    
    vector<ll> D(M), E(M), F(M);
    rep(i, M) cin >> D[i] >> E[i] >> F[i];
    
    vector<ll> xs;
    xs.push_back(-INF);
    xs.push_back(-1);
    xs.push_back(0);
    xs.push_back(1);
    xs.push_back(INF);
    rep(i, n) {
        for (int j=-1; j<=1; j++) xs.push_back(C[i]+j);
    }
    rep(i, M) {
        for (int j=-1; j<=1; j++) xs.push_back(E[i]+j);
        for (int j=-1; j<=1; j++) xs.push_back(F[i]+j);
    }
    sort(all(xs));
    xs.erase(unique(all(xs)), xs.end());

    vector<ll> ys;
    ys.push_back(-INF);
    ys.push_back(-1);
    ys.push_back(0);
    ys.push_back(1);
    ys.push_back(INF);
    rep(i, n) {
        for (int j=-1; j<=1; j++) ys.push_back(A[i]+j);
        for (int j=-1; j<=1; j++) ys.push_back(B[i]+j);
    }
    rep(i, M) {
        for (int j=-1; j<=1; j++) ys.push_back(D[i]+j);
    }
    sort(all(ys));
    ys.erase(unique(all(ys)), ys.end());

    ll H = ys.size(), W = xs.size();

   // vector<ll> a(n), b(n), c(n); 

    vector<vector<ll> > Z(H, vector<ll>(W));
    rep(i, n) {
        A[i] = lower_bound(all(ys), A[i]) - ys.begin();
        B[i] = lower_bound(all(ys), B[i]) - ys.begin();
        C[i] = lower_bound(all(xs), C[i]) - xs.begin();
        for(ll j = A[i]; j < B[i]; j++) {
            Z[j][C[i]] |= 1 << 0;
            Z[j][C[i]-1] |= 1 << 2;
        }
    }

//    vector<ll> d(M), e(M), f(M);
    rep(i, M) {
        D[i] = lower_bound(all(ys), D[i]) - ys.begin();
        E[i] = lower_bound(all(xs), E[i]) - xs.begin();
        F[i] = lower_bound(all(xs), F[i]) - xs.begin();
        for(ll j = E[i]; j < F[i]; j++) {
            Z[D[i]][j] |= 1 << 1;
            Z[D[i]-1][j] |= 1 << 3;
        }
    }

    // 正しくは(sx, sy)でなく、(sx+0.5, sy+0.5)にいると考える
    ll sx = lower_bound(all(xs), 0) - xs.begin();
    ll sy = lower_bound(all(ys), 0) - ys.begin();
    ll gx = lower_bound(all(xs), INF) - xs.begin();
    ll gy = lower_bound(all(ys), INF) - ys.begin();

    vector<vector<bool>> dp(H, vector<bool>(W, false));
    
    typedef pair<ll, ll> P;
    queue<P> que;
 
    que.push(P(sx, sy));
    dp[sy][sx] = 0;

    int dx[] = { -1, 0, 1, 0 };
    int dy[] = { 0, -1, 0, 1 };
    while (que.empty() == false) {
        P q = que.front();
        ll x = q.first;
        ll y = q.second;
        que.pop();

        rep(i, 4) {
            ll x2 = dx[i] + x;
            ll y2 = dy[i] + y;
            if (x2 < 0 || W <= x2 || y2 < 0 || H <= y2) {
                continue;
            }
            if (dp[y2][x2]) {
                // already visited
                continue;
            }
            if (Z[y][x] & (1 << i)) {
                // 壁で進めない
            }
            else {
                dp[y2][x2] = true;
                que.push(P(x2, y2));
            }
        }
    }

    if (dp[gy][gx]) {
        // 外にでれたらだめ
        put("INF");
    }
    else {
        ll res = 0;
        rep(y, H) rep(x, W) {
            if (dp[y][x] == false) {
                continue;
            }

            ll ddy = ys[y] - ys[y+1];
            ll ddx = xs[x] - xs[x+1];
            res += ddx * ddy;
        }
        
        put(res);
    }

}
signed main(){ Main();return 0;}

Measured memory_bytes: 647456