/* coordinate_compress_2D.cpp
    2Dの座標圧縮を行う

    verified: [AOJ] DSL_4_A Union of Rectangles
        http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_4_A&lang=ja
*/

#include <bits/stdc++.h>
using namespace std;
// 1次元 vector
template <class T>
ostream &operator<<(ostream &s, vector<T> vec) {
    for (int i = 0; i < (int)vec.size(); ++i) {
        if (i > 0) {
            s << " ";
        }
        s << vec[i];
    }
    return s << endl;
}
template <class T>  // 2次元 vector
ostream &operator<<(ostream &s, vector<vector<T>> vec2) {
    for (int i = 0; i < (int)vec2.size(); ++i) {
        s << vec2[i];
    }
    return s;
}
/* compress
    (X1,Y1),(X2,Y2)という二点で表されるもの（長方形や直線など）について、行か列の片方（X1とX2 or Y1とY2）を座標圧縮する（副作用）
    返り値: ソートされ重複要素を除いた値
    計算量: O(n log n)
*/
template <typename T>
vector<T> compress(vector<T> &C1, vector<T> &C2) {
    vector<T> vals;
    int N = (int)C1.size();
    for (int i = 0; i < N; i++) {
        T tc1 = C1[i];
        T tc2 = C2[i];
        vals.push_back(tc1);
        vals.push_back(tc2);
    }
    // ソート
    sort(vals.begin(), vals.end());
    // 隣り合う重複を削除(unique), 末端のゴミを削除(erase)
    vals.erase(unique(vals.begin(), vals.end()), vals.end());
    for (int i = 0; i < N; i++) {
        C1[i] = lower_bound(vals.begin(), vals.end(), C1[i]) - vals.begin();
        C2[i] = lower_bound(vals.begin(), vals.end(), C2[i]) - vals.begin();
    }
    return vals;
}

using ll = long long;

int main() {
    int N, M;
    cin >> N >> M;
    vector<long long> X1, Y1, X2, Y2;
    for (int i = 0; i < N; i++) {
        ll a, b, c;
        cin >> a >> b >> c;
        X1.push_back(a);
        X2.push_back(b);
        Y1.push_back(c);
        Y2.push_back(c);
    }
    for (int i = 0; i < M; i++) {
        ll a, b, c;
        cin >> a >> b >> c;
        X1.push_back(a);
        X2.push_back(a);
        Y1.push_back(b);
        Y2.push_back(c);
    }
    // 牛の位置
    X1.push_back(0);
    X2.push_back(0);
    Y1.push_back(0);
    Y2.push_back(0);

    vector<long long> X = compress(X1, X2);
    vector<long long> Y = compress(Y1, Y2);

    int H = X.size() * 2;
    int W = Y.size() * 2;
    vector<vector<int>> G(H, vector<int>(W));
    for (int i = 0; i < N; i++) {
        for (int x = X1[i] * 2; x <= X2[i] * 2; x++) {
            G[x][Y1[i] * 2] = -1;
        }
    }
    for (int i = N; i < N + M; i++) {
        for (int y = Y1[i] * 2; y <= Y2[i] * 2; y++) {
            G[X1[i] * 2][y] = -1;
        }
    }

    using P = pair<int, int>;
    P s(X1[N + M] * 2, Y1[N + M] * 2);
    G[s.first][s.second] = 1;
    //cerr << G;
    queue<pair<int, int>> que;
    que.emplace(s);
    while (que.size() != 0) {
        pair<int, int> now = que.front();
        que.pop();
        int dx[4] = {1, -1, 0, 0};
        int dy[4] = {0, 0, 1, -1};  // dx,dy は次の探索場所への距離を表す（４方向分）
        for (int i = 0; i < 4; i++) {
            int nx = now.first + dx[i];
            int ny = now.second + dy[i];
            if (nx < 0 || ny < 0 || H <= nx || W <= ny) continue;
            if (G[nx][ny] != 0) continue;  // 障害物があればスルー
            que.push(P(nx, ny));
            G[nx][ny] = 1;
        }
    }

    ll ans = 0;
    for (int x = 0; x < H; x++) {
        for (int y = 0; y < W; y++) {
            if (G[x][y] != 1) continue;
            if (x == 0 || H - 1 == x || y == 0 || W - 1 == y) {
                cout << "INF" << endl;
                return 0;
            }
            if (x % 2 == 0 || y % 2 == 0) continue;
            ans += (X[x / 2 + 1] - X[x / 2]) * (Y[y / 2 + 1] - Y[y / 2]);
        }
    }

    cout << ans << endl;
}


Measured memory_bytes: 144448