#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include <vector>
#include <sstream>
#include <string>
#include <functional>
#include <queue>
#include <stack>
#include <limits>
#include <unordered_map>
#include <unordered_set>
#include <math.h>
#include <fstream>
#include <iterator>
#include <random>
#include <chrono>
 
 
#define forr(i,start,count) for (int i = (start); i < (start)+(count); ++i)
#define set_map_includes(set, elt) (set.find((elt)) != set.end())
#define readint(i) int i; cin >> i
#define readll(i) ll i; cin >> i
#define readdouble(i) double i; cin >> i
#define readstring(s) string s; cin >> s
 
typedef long long ll;
 
using namespace std;

template<class T>
class depth_first_search_iterator {
  public:
    stack<pair<T,T>> todo;
    function<bool(T)> notvisited;
    function<void(T)> mark_visited;
    function<set<T>(T)> neighbors;

    depth_first_search_iterator() {}

    depth_first_search_iterator(T start, function<bool(T)> notv, function<void(T)> mark_v, function<set<T>(T)> neigh) :
      notvisited(notv), mark_visited(mark_v), neighbors(neigh), end_(false), current(start), prev(start) {
          todo.push(make_pair(start, start)); operator++();
    }

    void operator++() {
        end_ = true;
        while (!todo.empty()) {
            current = todo.top().first; prev = todo.top().second; todo.pop();
            if (notvisited(current)) {
                mark_visited(current);
                for (const T x : neighbors(current)) {  todo.push(make_pair(x, current));   }
                end_ = false;
                break;
            }
        }
    }

    T operator*() {     return current;    }

    T previous() {  return prev;  }

    bool end() {  return end_;  }

  private:
    T current; // contains current node
    T prev;    // contains previous node
    bool end_;
};
 
 
int main()   {
    cout.precision(17);
    ll modd = 1000 * 1000 * 1000 + 7;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    uniform_int_distribution<int> rand_gen(0, modd);   // rand_gen(rng) gets the rand no
    ll infinit = 10000000000000000;
 
//    readint(test_cases);
    int test_cases = 1;
    forr(t, 1, test_cases) {
        readint(n); readint(m);
        map<ll,int> xcoord, ycoord;
        xcoord[0] = 0; ycoord[0] = 0;
        map<ll,vector<pair<ll,ll>>> hor_lines, vert_lines;
        forr(i,0,n) {
            readll(a); readll(b); readll(c);
            xcoord[a] = 0; xcoord[b] = 0; ycoord[c] = 0;
            hor_lines[c].push_back(make_pair(a,b));
        }
        forr(i,0,m) {
            readll(d); readll(e); readll(f);
            xcoord[d] = 0; ycoord[e] = 0; ycoord[f] = 0;
            vert_lines[d].push_back(make_pair(e,f));
        }
        vector<ll> dict_x, dict_y;
        for (auto p : xcoord) {
            dict_x.push_back(p.first);
        }
        for (auto p : ycoord) {
            dict_y.push_back(p.first);
        }
        forr(i,0,dict_x.size()) {
            xcoord[dict_x[i]] = i;
        }
        forr(i,0,dict_y.size()) {
            ycoord[dict_y[i]] = i;
        }
 
        vector<vector<bool>> visited(dict_x.size(), vector<bool>(dict_y.size(), false));
        depth_first_search_iterator<pair<int,int>> bfs(make_pair(xcoord[0], ycoord[0]), [&visited, &dict_x, &dict_y](pair<int,int> x) {
            if ((x.first >= 0) && (x.first < dict_x.size()) && (x.second >= 0) && (x.second < dict_y.size())) {
              return (!visited[x.first][x.second]);
            } else {  return true;  }
        },        [&visited, &dict_y, &dict_x](pair<int,int> x) {
            if ((x.first >= 0) && (x.first < dict_x.size()) && (x.second >= 0) && (x.second < dict_y.size())) {
              visited[x.first][x.second] = true; }
        }, [&hor_lines, &vert_lines, &dict_x, &dict_y](pair<int,int> point) {
            set<pair<int,int>> ret;
            // left
            bool can_go = true;
            if ((point.first >= 0) && (point.first < dict_x.size()) && (point.second >= 0) && (point.second < dict_y.size())) {
              for (auto seg : vert_lines[dict_x[point.first]]) {  
                if ((seg.first <= dict_y[point.second]) && (seg.second > dict_y[point.second])) { can_go = false; break;  }   }
            }
            if (can_go) {  ret.insert(make_pair(point.first-1, point.second));  }
            // down
            can_go = true;
            if ((point.first >= 0) && (point.first < dict_x.size()) && (point.second >= 0) && (point.second < dict_y.size())) {
              for (auto seg : hor_lines[dict_y[point.second]]) {  
                if ((seg.first <= dict_x[point.first]) && (seg.second > dict_x[point.first])) { can_go = false; break;  }   }
            }
            if (can_go) {  ret.insert(make_pair(point.first, point.second-1));  }
            // right
            can_go = true;
            if ((point.first+1 >= 0) && (point.first+1 < dict_x.size()) && (point.second >= 0) && (point.second < dict_y.size())) {
              for (auto seg : vert_lines[dict_x[point.first+1]]) {  
                if ((seg.first <= dict_y[point.second]) && (seg.second > dict_y[point.second])) { can_go = false; break;  }   }
            }
            if (can_go) {  ret.insert(make_pair(point.first+1, point.second));  }
            // up
            can_go = true;
            if ((point.first >= 0) && (point.first < dict_x.size()) && (point.second+1 >= 0) && (point.second+1 < dict_y.size())) {
              for (auto seg : hor_lines[dict_y[point.second+1]]) {  
                if ((seg.first <= dict_x[point.first]) && (seg.second > dict_x[point.first])) { can_go = false; break;  }   }
            }
            if (can_go) {  ret.insert(make_pair(point.first, point.second+1));  }
 
            return ret;
        });
 
        ll ret = 0;
        bool infin = false;
        while (!bfs.end()) {
            if ((*bfs).first < 0) {  infin = true; break;  }
            if ((*bfs).second < 0) {  infin = true; break;  }
            if ((*bfs).first+1 >= dict_x.size()) {  infin = true; break;  }
            if ((*bfs).second+1 >= dict_y.size()) {  infin = true; break;  }
            ret += (dict_x[(*bfs).first+1] - dict_x[(*bfs).first]) * (dict_y[(*bfs).second+1] - dict_y[(*bfs).second]);
            ++bfs;
        }
 
        if (infin) {
          cout << "INF" << endl;
        } else {
          cout << ret << endl;
        }
    }
    return 0;
}

Measured memory_bytes: 128160