#if 1   // use_templates

#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <algorithm>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define rep(i, up) for (ll i = 0; i < up; ++i)
#define repp(i, up) for (ll i = 0; i <= up; ++i)
#define rrep(i, lo, up) for (ll i = lo; i < up; ++i)
#define rrepp(i, lo, up) for (ll i = lo; i <= up; ++i)
#define eep(i, lo, up) for ((i) = (lo); (i) < (up); ++(i))
#define eepp(i, lo, up) for ((i) = (lo); (i) <= (up); ++(i))

#define rdi(i) ll i; scanf("%lld", &i)
#define rds(s) string s; cin >> s
#define rdc(c) char c; cin >> c

#define INF 10000000000
#define MOD 1000000007


ll gcd(ll a, ll b);
template<class T>
auto fast_pow(T a, ll n);


template<class T, T n>
struct mod_t
{
    static_assert(n > 0, "invalid divisor");

    T value;

    constexpr mod_t() : value() { }
    constexpr mod_t(T x) : value(normalize(x)) { }
    constexpr mod_t(const mod_t& x) : value(normalize(x.value)) { }

    explicit constexpr operator T() const {
        return value;
    }
    constexpr auto operator+(mod_t<T, n> right) const {
        return mod_t<T, n> { (value + right.value) % n };
    }
    constexpr auto& operator+=(mod_t<T, n> right) {
        return *this = *this + right;
    }
    constexpr auto& operator++() {
        return *this = *this + mod_t<T, n>(1);
    }
    constexpr auto operator++(int) {
        decltype(*this) tmp(*this);
        *this = *this + mod_t<T, n>(1);
        return tmp;
    }
    constexpr auto operator-(mod_t<T, n> right) const {
        return mod_t<T, n> { (value - right.value + n) % n };
    }
    constexpr auto& operator-=(mod_t<T, n> right) {
        return *this = *this - right;
    }
    constexpr auto& operator--() {
        return *this = *this - mod_t<T, n>(1);
    }
    constexpr auto operator--(int) {
        decltype(*this) tmp(*this);
        *this = *this - mod_t<T, n>(1);
        return tmp;
    }
    constexpr auto operator*(mod_t<T, n> right) const {
        return mod_t<T, n> { (value * right.value) % n };
    }
    constexpr auto& operator*=(mod_t<T, n> right) {
        return *this = *this * right;
    }
    constexpr auto operator/(mod_t<T, n> right) const {
        return *this * right.pow(n - 2);
    }
    constexpr auto& operator/=(mod_t<T, n> right) {
        return *this = *this / right;
    }
    constexpr auto pow(ll nn) const {
        return fast_pow(*this, nn);
    }
    constexpr auto inv() const {
        return pow(n - 2);
    }

    static constexpr auto normalize(T x) {
        if (x < 0) {
            return (n + x % n) % n;
        } else {
            return x % n;
        }
    }
};
template<class T, T n>
auto& operator>>(istream& in, mod_t<T, n>& out) {
    T tmp;
    in >> tmp;
    out.value = mod_t<T, n>::normalize(tmp);
    return in;
}
template<class T, T n>
auto& operator<<(ostream& out, mod_t<T, n> val) {
    out << val.value;
    return out;
}
typedef mod_t<ll, MOD> mod;

template<class T, T n>
class combi_t
{
    using value_t = mod_t<T, n>;

    vector<value_t> factn;
    vector<value_t> ifactn;

    ll maxn;

public:
    combi_t() : factn(0), ifactn(0), maxn(0) { }

    combi_t(ll maxn)
        : factn(maxn + 1)
        , ifactn(maxn + 1)
    {
        init(maxn);
    }

    void init(ll maxn) {
        factn.resize(maxn + 1);
        ifactn.resize(maxn + 1);

        this->maxn = maxn;
        factn[0] = 1;
        ifactn[0] = 1;
        for (ll i = 1; i <= maxn; ++i) {
            factn[i] = i * factn[i - 1];
            ifactn[i] = value_t(i).inv() * ifactn[i - 1];
        }
    }

    constexpr auto combi(ll a, ll b) const {
        if (b <= 0 || a - b <= 0) {
            return value_t(1);
        } else {
            return factn[a] * ifactn[b] * ifactn[a - b];
        }
    }

    constexpr auto perm(ll a, ll b) const {
        return factn[a] * ifactn[a - b];
    }

    constexpr auto operator()(ll a, ll b) const {
        return combi(a, b);
    }
};
#define USE_COMBI(maxn) combi_t<ll, MOD> combi(maxn);

template<class T>
auto fast_pow(T a, ll n) {
    if (n <= 0) {
        return T(1);
    } else if (n == 1) {
        return T(a);
    } else if (n % 2 == 0) {
        auto work = fast_pow(a, n / 2);
        return work * work;
    } else {
        return fast_pow(a, n - 1) * a;
    }
}

ll gcd(ll a, ll b)
{
    if (a < b) {
        return gcd(b, a);
    }
    ll r;
    while (r = a % b) {
        a = b;
        b = r;
    }
    return b;
}

template<class T>
void read_vec(vector<T>& v, ll n)
{
    v.resize(n);
    for (ll i = 0; i < n; ++i) {
        cin >> v[i];
    }
}
template<>
void read_vec<ll>(vector<ll>& v, ll n) {
    v.resize(n);
    for (ll i = 0; i < n; ++i) {
        scanf("%lld", &v[i]);
    }
}
template<class T>
auto read_vec(ll n) {
    vector<T> result;
    read_vec(result, n);
    return result;
}
void read_idxs(vector<ll>& v, ll n) {
    v.resize(n);
    for (ll i = 0; i < n; ++i) {
        scanf("%lld", &v[i]);
        --v[i];
    }
}
auto read_idxs(ll n) {
    vector<ll> result(n);
    for (ll i = 0; i < n; ++i) {
        scanf("%lld", &result[i]);
        --result[i];
    }
    return result;
}
template<class T>
void read_mat(vector<vector<T>>& v, ll n, ll m) {
    v.resize(n);
    for (ll i = 0; i < n; ++i) {
        read_vec(v[i], m);
    }
}
template<class T>
auto read_mat(ll n, ll m) {
    vector<T> result(n);
    for (ll i = 0; i < n; ++i) {
        read_vec(result[i], m);
    }
    return result;
}

#endif  // end of use_templates


int main()
{
    int n, m;
    cin >> n >> m;
    vector<pair<pair<ll, ll>, ll>> is(n);
    vector<pair<ll, pair<ll, ll>>> js(m);
    set<ll> xss;
    set<ll> yss;
    rep(i, n) {
        cin >> is[i].first.first >> is[i].first.second >> is[i].second;
        xss.insert(is[i].first.first);
        xss.insert(is[i].first.second);
        yss.insert(is[i].second);
    }
    rep(i, m) {
        cin >> js[i].first >> js[i].second.first >> js[i].second.second;
        xss.insert(js[i].first);
        yss.insert(js[i].second.first);
        yss.insert(js[i].second.second);
    }
    vector<ll> xs(xss.begin(), xss.end());
    vector<ll> ys(yss.begin(), yss.end());
    map<ll, ll> xis;
    map<ll, ll> yis;
    for (auto it = xs.begin(); it != xs.end(); ++it) {
        xis[*it] = it - xs.begin();
    }
    for (auto it = ys.begin(); it != ys.end(); ++it) {
        yis[*it] = it - ys.begin();
    }
    vector<ll> xds(xs.size() - 1);
    vector<ll> yds(ys.size() - 1);
    rrep(i, 1, xs.size()) {
        xds[i - 1] = xs[i] - xs[i - 1];
    }
    rrep(i, 1, ys.size()) {
        yds[i - 1] = ys[i] - ys[i - 1];
    }
    vector<vector<bool>> hwall(xds.size());
    vector<vector<bool>> vwall(yds.size());
    rep(i, hwall.size()) {
        hwall[i].resize(yds.size() + 1, false);
    }
    rep(i, vwall.size()) {
        vwall[i].resize(xds.size() + 1, false);
    }
    rep(i, is.size()) {
        ll left = xis[is[i].first.first];
        ll right = xis[is[i].first.second];
        ll y = yis[is[i].second];
        rrep(i, left, right) {
            hwall[i][y] = true;
        }
    }
    rep(i, js.size()) {
        ll x = xis[js[i].first];
        ll bottom = yis[js[i].second.first];
        ll top = yis[js[i].second.second];
        rrep(i, bottom, top) {
            vwall[i][x] = true;
        }
    }
    vector<vector<ll>> field(xds.size());
    rep(i, field.size()) {
        field[i].resize(yds.size());
        rep(j, field[i].size()) {
            field[i][j] = xds[i] * yds[j];
        }
    }
    auto xit = lower_bound(xs.begin(), xs.end(), 0);
    auto yit = lower_bound(ys.begin(), ys.end(), 0);
    if (xit == xs.end() || yit == ys.end()) {
        cout << "INF" << endl;
        return 0;
    }
    ll result = 0;
    queue<pair<ll, ll>> que;
    que.emplace(xit - xs.begin(), yit - ys.begin());
    while (!que.empty()) {
        auto p = que.front();
        que.pop();
        if (p.first < 0 || field.size() <= p.first || p.second < 0 || field[p.first].size() <= p.second || field[p.first][p.second] < 0) {
            continue;
        }
        result += field[p.first][p.second];
        field[p.first][p.second] = -1;
        if (!hwall[p.first][p.second]) {
            if (p.second == 0) {
                cout << "INF" << endl;
                return 0;
            }
            que.emplace(p.first, p.second - 1);
        }
        if (!hwall[p.first][p.second + 1]) {
            if (p.second == hwall[p.first].size() - 1) {
                cout << "INF" << endl;
                return 0;
            }
            que.emplace(p.first, p.second + 1);
        }
        if (!vwall[p.second][p.first]) {
            if (p.first == 0) {
                cout << "INF" << endl;
                return 0;
            }
            que.emplace(p.first - 1, p.second);
        }
        if (!vwall[p.second][p.first + 1]) {
            if (p.first == vwall[p.second].size() - 1) {
                cout << "INF" << endl;
                return 0;
            }
            que.emplace(p.first + 1, p.second);
        }
    }
    cout << result << endl;
    return 0;
}
