#include <cstdio> 
#include <cstdlib> 
#include <cmath> 
#include <cstring> 
#include <climits> 
#include <cfloat> 
#include <map> 
#include <utility> 
#include <set> 
#include <iostream> 
#include <memory> 
#include <string> 
#include <vector> 
#include <algorithm> 
#include <functional> 
#include <sstream> 
#include <complex> 
#include <stack> 
#include <queue> 
#include <numeric>
#include <cassert>

#define FOR(i, min, max) for (int i = (min); i < (max); ++i) 
#define FORE(i, min, max) for (int i = (min); i <= (max); ++i) 
#define REP(i, n) for (int i = 0; i < (n); ++i) 
#define REPV(vec, i) for (int i = 0; i < (int)(vec.size()); ++i) 
#define FOR_EACH(vec, it) for (typeof((vec).begin()) it = (vec).begin(); it != (vec).end(); ++it)

using namespace std; 
static const double EPS = 1e-12; 
typedef long long ll; 

template<typename T>
struct PointCompress {
    std::map<T, int> allP;
    std::vector<T> rmap;

  public:
    int size(void) {
        return allP.size();
    }
    
    void add(T n) {
        allP[n-1] = -1;
        allP[n] = -1;
        allP[n+1] = -1;
    }
    
    void add(vector<T> &v) {
        for (auto n : v) add(n);
    }

    void build(void) {
        int n = 0;
        rmap.clear();
        for (auto &it : allP) {
            it.second = n++;
            rmap.push_back(it.first);
        }
    }

    int convert(T val) {
        return allP[val];
    }

    vector<int> convert(const vector<T> &v) {
        vector<int> ret;
        for (auto &n : v) ret.push_back(convert(n));
        return ret;
    }

    pair<T, T> getCellRange(int i) {
        int N = size();
        assert(i < N-1);
        return pair<T, T>{rmap[i], rmap[i+1]};
    }

    T getCellLength(int i) {
        auto p = getCellRange(i);
        return (p.second - p.first);
    }
};

int DX[4] = {-1, 0, 1, 0};
int DY[4] = {0, -1, 0, 1};

int main(void)
{
    int N, M;
    cin >> N >> M;
    vector<int> x0(N), x1(N), yc(N);
    REP(i, N)
        cin >> x0[i] >> x1[i] >> yc[i];
    vector<int> y0(M), y1(M), xc(M);
    REP(i, M)
        cin >> xc[i] >> y0[i] >> y1[i];

    PointCompress<int> cpx;
    cpx.add(0);
    cpx.add(x0); cpx.add(x1); cpx.add(xc);
    cpx.build();
    x0 = cpx.convert(x0);
    x1 = cpx.convert(x1);
    xc = cpx.convert(xc);

    PointCompress<int> cpy;
    cpy.add(0);
    cpy.add(y0); cpy.add(y1); cpy.add(yc);
    cpy.build();
    y0 = cpy.convert(y0);
    y1 = cpy.convert(y1);
    yc = cpy.convert(yc);

    int H = cpy.size();
    int W = cpx.size();
    int startx = cpx.convert(0);
    int starty = cpy.convert(0);
    vector<vector<bool> > visited(H, vector<bool>(W, false));
    vector<vector<bool> > cantGo[4];

    REP(k, 4) cantGo[k] = visited;
    REP(i, M) {
        // k = 0 (dx = -1)
        FOR(y, y0[i], y1[i]) cantGo[0][y][xc[i]] = true;
        // k = 2 (dx = 1)
        FOR(y, y0[i], y1[i]) cantGo[2][y][xc[i]-1] = true;
    }
    REP(i, N) {
        // k = 1 (dy = -1)
        FOR(x, x0[i], x1[i]) cantGo[1][yc[i]][x] = true;
        // k = 3 (dy = 1)
        FOR(x, x0[i], x1[i]) cantGo[3][yc[i]-1][x] = true;
    }

    queue<pair<int, int> > Q;
    visited[starty][startx] = true;
    Q.push({startx, starty});
    while(!Q.empty()) {
        int x = Q.front().first;
        int y = Q.front().second;
        Q.pop();
        REP(k, 4) if (!cantGo[k][y][x]) {
            int nx = x + DX[k];
            int ny = y + DY[k];
            if (nx < 0 || nx >= W || ny < 0 || ny >= H) {
                cout << "INF" << endl;
                return 0;
            }
            if (!visited[ny][nx]) {
                visited[ny][nx] = true;
                Q.push({nx, ny});
            }
        }
    }

    ll area = 0;
    REP(y, H) REP(x, W) {
        if (visited[y][x]) {
            area += (ll)cpx.getCellLength(x) * (ll)cpy.getCellLength(y);
        }
    }
    cout << area << endl;
    
    return 0;
}


Measured memory_bytes: 56076