#include <iostream>
#include <iomanip>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <array>
#include <tuple>
#include <string>
#include <algorithm>
#include <functional> // greater など
#include <cmath>      // abs など
#include <numeric>    // accumulate, gcd など
#include <cassert>    // assert
#include <stdexcept>
#include <bitset>
using namespace std;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, a, b) for (int i = (a); i < (int)(b); i++)
typedef long long ll;

#define _GLIBCXX_DEBUG
#define _LIBCPP_DEBUG 0

//////////////// //////////////// //////////////// //////////////// ////////////////
//////////////// //////////////// //////////////// //////////////// ////////////////

constexpr int x_infty = 1000'000'000 + 1;

vector<int> dx = {1, 0, -1, 0}, dy = {0, 1, 0, -1};

void dfs(int x_cmp, int y_cmp, vector<int> &x_s, vector<int> &y_s, vector<vector<vector<bool>>> &is_wall, vector<vector<bool>> &used, bool &is_infty, ll &ans)
{
    if (used[x_cmp][y_cmp])
    {
        return;
    }
    used[x_cmp][y_cmp] = true;
    if (x_cmp == 0 || x_cmp + 2 == (int)x_s.size() || y_cmp == 0 || y_cmp + 2 == (int)y_s.size())
    {
        is_infty = true;
        return;
    }
    ans += ((ll)x_s[x_cmp + 1] - x_s[x_cmp]) * ((ll)y_s[y_cmp + 1] - y_s[y_cmp]);
    // clog << "x " << x_cmp << " y " << y_cmp << " ans " << ans << "\n";
    rep(i, 4)
    {
        if (is_wall[x_cmp][y_cmp][i])
        {
            continue;
        }
        dfs(x_cmp + dx[i], y_cmp + dy[i], x_s, y_s, is_wall, used, is_infty, ans);
    }
}

int main()
{
    // 高速な入出力
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << setprecision(15); // 浮動小数の表示の精度

    int n, m;
    cin >> n >> m;
    vector<int> x_s = {-x_infty, 0, x_infty}, y_s = {-x_infty, 0, x_infty};
    vector<int> vert_x1(n), vert_x2(n), vert_y(n);
    rep(i, n)
    {
        cin >> vert_x1[i] >> vert_x2[i] >> vert_y[i];
        x_s.push_back(vert_x1[i]);
        x_s.push_back(vert_x2[i]);
        y_s.push_back(vert_y[i]);
    }
    vector<int> hori_x(n), hori_y1(n), hori_y2(n);
    rep(k, m)
    {
        cin >> hori_x[k] >> hori_y1[k] >> hori_y2[k];
        x_s.push_back(hori_x[k]);
        y_s.push_back(hori_y1[k]);
        y_s.push_back(hori_y2[k]);
    }
    sort(x_s.begin(), x_s.end());
    sort(y_s.begin(), y_s.end());
    x_s.erase(unique(x_s.begin(), x_s.end()), x_s.end());
    y_s.erase(unique(y_s.begin(), y_s.end()), y_s.end());
    /*
    rep(i, x_s.size()) { clog << x_s[i] << ' '; }
    clog << '\n';
    rep(k, y_s.size()) { clog << y_s[k] << ' '; }
    clog << '\n';
    */

    // (x_cmp,y_cmp) を左上に持つ長方形も (x_cmp,y_cmp) と書く
    // is_wall[x_cmp][y_cmp][i] = (x_cmp,y_cmp) to (x_cmp+dx[i],y_cmp+dy[i]) が壁か?
    vector<vector<vector<bool>>> *is_wall = new vector<vector<vector<bool>>>(x_s.size() - 1, vector<vector<bool>>(y_s.size() - 1, vector<bool>(4, false)));
    // vector<vector<vector<char>>> is_wall(x_s.size() - 1, vector<vector<char>>(y_s.size() - 1, vector<char>(4, false)));
    rep(i, n)
    {
        int x1_cmp = lower_bound(x_s.begin(), x_s.end(), vert_x1[i]) - x_s.begin();
        int x2_cmp = lower_bound(x_s.begin(), x_s.end(), vert_x2[i]) - x_s.begin();
        int y_cmp = lower_bound(y_s.begin(), y_s.end(), vert_y[i]) - y_s.begin();
        for (int x_cmp = x1_cmp; x_cmp < x2_cmp; x_cmp++)
        {
            (*is_wall)[x_cmp][y_cmp - 1][1] = (*is_wall)[x_cmp][y_cmp][3] = true;
            // clog << "x " << x_cmp << " y " << y_cmp << "\n";
        }
    }
    rep(k, m)
    {
        int x_cmp = lower_bound(x_s.begin(), x_s.end(), hori_x[k]) - x_s.begin();
        int y1_cmp = lower_bound(y_s.begin(), y_s.end(), hori_y1[k]) - y_s.begin();
        int y2_cmp = lower_bound(y_s.begin(), y_s.end(), hori_y2[k]) - y_s.begin();
        for (int y_cmp = y1_cmp; y_cmp < y2_cmp; y_cmp++)
        {
            (*is_wall)[x_cmp - 1][y_cmp][0] = (*is_wall)[x_cmp][y_cmp][2] = true;
            // clog << "x " << x_cmp << " y " << y_cmp << "\n";
        }
    }
    /*
    rep(i, x_s.size() - 1)
    {
        rep(k, y_s.size() - 1)
        {
            clog << (x_s[i] == 0 && y_s[k] == 0 ? '*' : ' ') << ((bool)is_wall[i][k][1] ? '|' : ' ');
        }
        clog << '\n';
        rep(k, y_s.size() - 1)
        {
            clog << ((bool)is_wall[i][k][0] ? '-' : ' ') << ' ';
        }
        clog << '\n';
    }
     */

    bool is_infty = false;
    ll ans = 0;
    vector<vector<bool>> *used = new vector<vector<bool>>(x_s.size() - 1, vector<bool>(y_s.size() - 1, false));
    /*
    auto is_edge_x = [&](int x_cmp) { return x_cmp == 0 || x_cmp + 2 == x_s.size(); };
    auto is_edge_y = [&](int y_cmp) { return y_cmp == 0 || y_cmp + 2 == y_s.size(); };
     */
    /*
    auto dfs = [&](auto self, int x_cmp, int y_cmp) {
        if (used[x_cmp][y_cmp])
        {
            return;
        }
        used[x_cmp][y_cmp] = true;
        if (is_edge_x(x_cmp) || is_edge_y(y_cmp))
        {
            is_infty = true;
            return;
        }
        ans += ((ll)x_s[x_cmp + 1] - x_s[x_cmp]) * ((ll)y_s[y_cmp + 1] - y_s[y_cmp]);
        // clog << "x " << x_cmp << " y " << y_cmp << " ans " << ans << "\n";
        rep(i, 4)
        {
            if (is_wall[x_cmp][y_cmp][i])
            {
                continue;
            }
            self(self, x_cmp + dx[i], y_cmp + dy[i]);
        }
    };
     */
    int x0 = lower_bound(x_s.begin(), x_s.end(), 0) - x_s.begin();
    int y0 = lower_bound(y_s.begin(), y_s.end(), 0) - y_s.begin();
    // dfs(dfs, x0, y0);
    dfs(x0, y0, x_s, y_s, *is_wall, *used, is_infty, ans);
    if (is_infty)
    {
        cout << "INF\n";
    }
    else
    {
        cout << ans << '\n';
    }

    return 0;
}
