#include <bits/stdc++.h>
using namespace std;
#define int long long

signed main(){
    // cout << fixed << setprecision(10) << flush;

    int n, m;
    cin >> n >> m;
    vector<int> a(n), b(n), c(n);
    vector<int> old_x(2*n+m);
    vector<int> old_y(n+2*m);
    for(int i=0; i<n; i++){
        cin >> a[i] >> b[i] >> c[i];
        old_x[2*i] = a[i];
        old_x[2*i+1] = b[i];
        old_y[i] = c[i];
    }
    vector<int> d(m), e(m), f(m);
    for(int i=0; i<m; i++){
        cin >> d[i] >> e[i] >> f[i];
        old_x[2*n+i] = d[i];
        old_y[n+2*i] = e[i];
        old_y[n+2*i+1] = f[i];
    }

    sort(old_x.begin(), old_x.end());
    old_x.erase(unique(old_x.begin(), old_x.end()), old_x.end());
    sort(old_y.begin(), old_y.end());
    old_y.erase(unique(old_y.begin(), old_y.end()), old_y.end());

    map<int, int> new_x, new_y;
    for(int i=0; i<old_x.size(); i++){
        new_x[old_x[i]] = i;
    }
    for(int i=0; i<old_y.size(); i++){
        new_y[old_y[i]] = i;
    }
    
    // 真に中なのは 1-origin
    // ver_edge[i][j] は (i, j) <-> (i, j+1) があるかどうか
    // hor_edge[i][j] は (i, j) <-> (i+1, j) があるかどうか
    vector<vector<int>> ver_edge(old_x.size()+1, vector<int>(old_y.size()+1, 1));
    vector<vector<int>> hor_edge(old_x.size()+1, vector<int>(old_y.size()+1, 1));
    for(int i=0; i<n; i++){
        int new_j = new_y[c[i]];
        for(int new_i=new_x[a[i]]; new_i<new_x[b[i]]; new_i++){
            ver_edge[new_i+1][new_j] = 0;
        }
    }
    for(int i=0; i<m; i++){
        int new_i = new_x[d[i]];
        for(int new_j=new_y[e[i]]; new_j<new_y[f[i]]; new_j++){
            hor_edge[new_i][new_j+1] = 0;
        }
    }

    vector<vector<int>> visited(old_x.size()+1, vector<int>(old_y.size()+1, 0));
    auto itrx_l = lower_bound(old_x.begin(), old_x.end(), 0);
    auto itrx_u = upper_bound(old_x.begin(), old_x.end(), 0);
    int i_l = distance(old_x.begin(), itrx_l);
    int i_u = distance(old_x.begin(), itrx_u);
    if(i_l == 0 || i_u >= old_x.size()){
        // 0 は範囲外
        cout << "INF" << endl;
        return 0;
    }
    auto itry_l = lower_bound(old_y.begin(), old_y.end(), 0);
    auto itry_u = upper_bound(old_y.begin(), old_y.end(), 0);
    int j_l = distance(old_y.begin(), itry_l);
    int j_u = distance(old_y.begin(), itry_u);
    if(j_l == 0 || j_u >= old_y.size()){
        // 0 は範囲外
        cout << "INF" << endl;
        return 0;
    }

    // 開始位置、すなわち (0,0) が含まれているマスを queue にいれる
    queue<int> qi;
    queue<int> qj;
    for(int i=i_l; i<=i_u; i++){
        for(int j=j_l; j<=j_u; j++){
            qi.push(i);
            qj.push(j);
            visited[i][j] = 1;
        }
    }

    auto is_around = [&](int i, int j){
        return i == 0 || i == old_x.size()+1 || j == 0 || j == old_y.size()+1;
    };

    while(!qi.empty()){
        int nowi = qi.front();
        int nowj = qj.front();
        if(is_around(nowi, nowj)){
            cout << "INF" << endl;
            return 0;
        }
        qi.pop();
        qj.pop();

        int di[4] = {0, 0, 1, -1};
        int dj[4] = {1, -1, 0, 0};
        for(int k=0; k<4; k++){
            int nexti = nowi + di[k];
            int nextj = nowj + dj[k];
            if((di[k] == 0 && ver_edge[nowi][nowj + (dj[k]-1)/2]) == 1 || (dj[k] == 0 && hor_edge[nowi + (di[k]-1)/2][nowj] == 1)){
                // 道がある
                if(is_around(nexti, nextj)){
                    cout << "INF" << endl;
                    return 0;
                }
                if(visited[nexti][nextj] != 0) continue;
                visited[nexti][nextj] = 1;
                qi.push(nexti);
                qj.push(nextj);
            }
        }
    }

    int area = 0;
    for(int i=0; i<old_x.size()-1; i++){
        for(int j=0; j<old_y.size()-1; j++){
            if(visited[i+1][j+1] == 1){
                area += (old_x[i+1] - old_x[i]) * (old_y[j+1] - old_y[j]);
            }
        }
    }
    cout << area << endl;

    return 0;
}

Measured memory_bytes: 215260