#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <string>
#include <map>
#include <set>
#include <stack>
#include <tuple>
#include <deque>
#include <numeric>
#include <bitset>
#include <iomanip>
#include <cassert>
#include <chrono>
#include <random>
#include <limits>
#include <iterator>
#include <functional>
#include <sstream>
#include <complex>
using namespace std;

using ll = long long;
using ull = uint64_t;
using P = pair<int, int>;
constexpr double EPS = 1e-9;
constexpr int INF = 1001001001;
constexpr int mod = 1000000007;
// constexpr int mod = 998244353;

template<class T>
inline bool chmax(T& x, T y){
    if(x < y){
        x = y;
        return true;
    }
    return false;
}
template<class T>
inline bool chmin(T& x, T y){
    if(x > y){
        x = y;
        return true;
    }
    return false;
}

template<typename T>
struct Compress{
    vector<T> xs;
    Compress() = default;
    Compress(const vector<T> &vs){
        add(vs);
    }
    Compress(const initializer_list<vector<T>> &vs){
        for(auto &p : vs)   add(p);
    }

    // vs 内の座標をすべて追加
    void add(const vector<T> &vs){
        copy(begin(vs), end(vs), back_inserter(xs));
    }

    void add(const T &x){
        xs.emplace_back(x);
    }
    
    void build(){
        sort(begin(xs), end(xs));
        xs.erase(unique(begin(xs), end(xs)), end(xs));
    }

    // vs 内の座標を座標圧縮したものを返す
    vector<int> get(const vector<T> &vs) const{
        vector<int> ret;
        transform(begin(vs), end(vs), back_inserter(ret), [&](const T &x){
            return lower_bound(begin(xs), end(xs), x) - begin(xs);
        });
        return ret;
    }

    // 座標 x を座標圧縮したものを返す (x が xs 内で何番目にあるかを返す)
    int get(const T &x) const{
        return lower_bound(begin(xs), end(xs), x) - begin(xs);
    }

    // 座標圧縮後の k が示す実際の座標を返す
    const T &operator[](int k) const{
        return xs[k];
    }
};

constexpr int dx[4] = {1, 0, -1, 0};
constexpr int dy[4] = {0, 1, 0, -1};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;
    Compress<int> cx, cy;
    vector<int> a(n), b(n), c(n), d(m), e(m), f(m);
    for(int i = 0; i < n; ++i){
        cin >> a[i] >> b[i] >> c[i];
        cx.add(a[i]), cx.add(b[i]);
        cy.add(c[i]);
    }
    for(int i = 0; i < m; ++i){
        cin >> d[i] >> e[i] >> f[i];
        cx.add(d[i]);
        cy.add(e[i]), cy.add(f[i]);
    }
    cx.add(0), cy.add(0);
    cx.build();
    cy.build();
    
    int h = cx.xs.size() * 2, w = cy.xs.size() * 2;
    vector<vector<int>> Visitable(h, vector<int>(w, 0));
    for(int i = 0; i < n; ++i){
        int p = cy.get(c[i]) * 2;
        for(int x = cx.get(a[i]) * 2; x <= cx.get(b[i]) * 2; ++x){
            Visitable[x][p] = -1;
        }
    }
    for(int i = 0; i < m; ++i){
        int p = cx.get(d[i]) * 2;
        for(int y = cy.get(e[i]) * 2; y <= cy.get(f[i]) * 2; ++y){
            Visitable[p][y] = -1;
        }
    }

    int sx = cx.get(0) * 2, sy = cy.get(0) * 2;
    queue<P> que;
    Visitable[sx][sy] = 1;
    que.emplace(sx, sy);
    while(!que.empty()){
        int x = que.front().first;
        int y = que.front().second;
        que.pop();
        for(int i = 0; i < 4; ++i){
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 0 || nx >= h || ny < 0 || ny >= w)  continue;
            if(Visitable[nx][ny] != 0)  continue;
            Visitable[nx][ny] = 1;
            que.emplace(nx, ny);
        }
    }

    ll ans = 0;
    for(int i = 0; i < h; ++i){
        for(int j = 0; j < w; ++j){
            if(Visitable[i][j] != 1)    continue;
            if(i == 0 || i == h - 1 || j == 0 || j == w - 1){
                cout << "INF\n";
                return 0;
            }
            if(i % 2 == 0 || j % 2 == 0)    continue;
            int d1 = cx[i / 2 + 1] - cx[i / 2];
            int d2 = cy[j / 2 + 1] - cy[j / 2];
            ans += (ll)d1 * d2;
        }
    }
    cout << ans << endl;
}

Measured memory_bytes: 144136