#include <bits/stdc++.h>  // clang-format off
using Int = long long;
#define REP_(i, a_, b_, a, b, ...) for (Int i = (a), lim##i = (b); i < lim##i; i++)
#define REP(i, ...) REP_(i, __VA_ARGS__, __VA_ARGS__, 0, __VA_ARGS__)
struct SetupIO { SetupIO() { std::cin.tie(nullptr), std::ios::sync_with_stdio(false), std::cout << std::fixed << std::setprecision(13); } } setup_io;
#ifndef dump
#define dump(...)
#endif  // clang-format on

/**
 *    author:  knshnb
 *    created: Sun May 17 22:10:44 JST 2020
 **/

template <class A, class B, class C, class D>
std::pair<A, B>& operator+=(std::pair<A, B>& x, const std::pair<C, D>& y) {
    return x = {x.first + y.first, x.second + y.second};
}
template <class A, class B, class C, class D> std::pair<A, B> operator+(std::pair<A, B> x, const std::pair<C, D>& y) {
    return x += y;
}

const std::vector<std::pair<int, int>> DIRECTIONS = {
    {1, 0}, {0, 1}, {-1, 0}, {0, -1},  // 4方向
};

template <class T, class S> T make_vec(S x) { return x; }
template <class T, class... Ts> auto make_vec(size_t n, Ts... ts) {
    return std::vector<decltype(make_vec<T>(ts...))>(n, make_vec<T>(ts...));
}

template <class T> struct Compressor {
    std::vector<T> val;
    void insert(T x) { val.push_back(x); }
    void insert(const std::vector<T>& v) { val.insert(val.begin(), v.begin(), v.end()); }
    void build() {
        std::sort(val.begin(), val.end());
        val.erase(std::unique(val.begin(), val.end()), val.end());
    }
    int operator()(T x) { return std::lower_bound(val.begin(), val.end(), x) - val.begin(); }
    T operator[](int idx) { return val[idx]; }
    int size() { return val.size(); }
};

// 0-indexed
// t.add(i0, j0, i1, j1) -> t.run() -> t[i][j]
template <class T> struct Imos2D {
    int n, m;
    std::vector<std::vector<T>> t;  // 0-indexed!!, -x分のために配列の外側を1大きめに
    Imos2D(int n_, int m_) : n(n_), m(m_), t(n_ + 1, std::vector<T>(m_ + 1)) {}
    // i0 <= i < i1, j0 < j < j1の範囲に+x
    void add(int i0, int j0, int i1, int j1, T x) {
        t[i0][j0] += x, t[i1][j1] += x;
        t[i1][j0] -= x, t[i0][j1] -= x;
    }
    // 2方向に累積和をとる
    void build() {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) t[i + 1][j] += t[i][j];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) t[i][j + 1] += t[i][j];
    }
    std::vector<T>& operator[](int i) { return t[i]; }
};

using pii = std::pair<int, int>;
signed main() {
    Compressor<Int> cp;
    cp.insert(0);
    Int n, m;
    std::cin >> n >> m;
    std::vector<Int> a(n), b(n), c(n), d(m), e(m), f(m);
    REP(i, n) std::cin >> a[i] >> b[i] >> c[i];
    REP(i, m) std::cin >> d[i] >> e[i] >> f[i];
    for (auto& v : {&a, &b, &c, &d, &e, &f}) {
        cp.insert(*v);
    }
    cp.build();
    Int K = cp.size();
    Imos2D<int> t(2 * K + 2, 2 * K + 2);
    auto enc = [&](Int val) { return 2 * cp(val) + 1; };
    REP(i, n) { t.add(enc(a[i]), enc(c[i]), enc(b[i]) + 1, enc(c[i]) + 1, 1); }
    REP(i, m) { t.add(enc(d[i]), enc(e[i]), enc(d[i]) + 1, enc(f[i]) + 1, 1); }
    t.build();

    std::queue<pii> q;
    q.push({enc(0), enc(0)});
    t[enc(0)][enc(0)] = true;
    Int ans = 0;
    while (!q.empty()) {
        pii p = q.front();
        q.pop();
        for (auto dir : DIRECTIONS) {
            pii nxt = p + dir;
            if (t[nxt.first][nxt.second]) continue;
            if (nxt.first == 0 || nxt.first == 2 * K + 1 || nxt.second == 0 || nxt.second == 2 * K + 1) {
                std::cout << "INF" << std::endl;
                return 0;
            }
            t[nxt.first][nxt.second] = true;
            q.push(nxt);
            if (nxt.first % 2 == 0 && nxt.second % 2 == 0) {
                Int i = nxt.first / 2, j = nxt.second / 2;
                ans += (cp[i] - cp[i - 1]) * (cp[j] - cp[j - 1]);
            }
        }
    }
    std::cout << ans << std::endl;
}


Measured memory_bytes: 566816