#include<iostream>
#include<queue>
#include<map>
#include<algorithm>
#include<cstdint>
#include<cassert>
#include<cstdlib>
template<typename T>
void fin(T const& t){ std::cout << t << std::endl; exit(0); }

struct line { int64_t p, q, r; line(){} };
template<typename T>
void sort_u(T& v) {
  std::sort(v.begin(), v.end());
  v.erase(std::unique(v.begin(),v.end()), v.end());
}
template<typename T>
std::vector<std::vector<T>> mk2d(size_t s1, size_t s2, T const& val) {
  std::vector<T> tmp(s2, val);
  return std::vector<std::vector<T>>(s1, tmp);
}

template<typename T>
struct point {
  T x, y;
  point(T const& in_x = 0, T const& in_y = 0): x(in_x), y(in_y) {}
  point operator +=(point const& r){ x += r.x; y += r.y; return *this; }
  point operator +(point const& r) const { point res(*this); return res += r; }
  //point operator -=(point const& r){ x -= r.x; y -= r.y; return *this; }
  //point operator -(point const& r) const { point res(*this); return res -= r; }
};

template<typename T>
struct move4 {
  using point_type = point<T>;
  point_type const d[4] = {{-1,0},{0,-1},{1,0},{0,1}};
  std::pair<point_type, point_type> res[4];
  move4() {};
  void go(point_type const& p) {
    for(int i = 0; i < 4; ++i) {
      res[i].first = p + d[i];
      res[i].second = res[i].first + d[i];
    }
  }
};

int main() {
  int N, M; std::cin >> N >> M;
  std::vector<int> xs(M), ys(N);
  std::vector<line> lh(N), lv(M);
  // (p...q, r) / (p, q...r)
  for(int i = 0; i < N; ++i) { std::cin >> lh[i].p >> lh[i].q >> lh[i].r; ys[i]=lh[i].r; }
  for(int i = 0; i < M; ++i) { std::cin >> lv[i].p >> lv[i].q >> lv[i].r; xs[i]=lv[i].p; }
  sort_u(xs); sort_u(ys);
  if(xs[0] >= 0 || xs.back() <= 0 || ys[0] >= 0 || ys.back() <= 0) fin("INF");
  
  // walls
  int XS = xs.size(), YS = ys.size();
  auto w_xy = mk2d(XS*2-1, YS*2-1, 0);
  for(auto const& w: lh) { // w.p < w.q : given
    int x1 = std::max(0, (int)(std::lower_bound(xs.begin(), xs.end(), w.p) - xs.begin()));
    int x2 = std::min(XS, (int)(std::upper_bound(xs.begin(), xs.end(), w.q) - xs.begin()))-1;
    if(x2 <= 0 || x1 >= XS-1) continue;
    int y  = std::lower_bound(ys.begin(), ys.end(), w.r) - ys.begin();
    x1 *= 2; y *= 2; x2 *= 2;
    for(int x = x1; x <= x2; ++x) w_xy[x][y] = 1;
  }
  for(auto const& w: lv) { // w.q < w.r : given
    int x  = std::lower_bound(xs.begin(), xs.end(), w.p) - xs.begin();
    int y1 = std::max(0, (int)(std::lower_bound(ys.begin(), ys.end(), w.q) - ys.begin()));
    int y2 = std::min(YS, (int)(std::upper_bound(ys.begin(), ys.end(), w.r) - ys.begin()))-1;
    if(y2 <= 0 || y1 >= YS-1) continue;
    x *= 2; y1 *= 2; y2 *= 2;
    for(int y = y1; y <= y2; ++y) w_xy[x][y] = 1;
  }
  // bfs
  auto visited_xy = mk2d<bool>(XS-1, YS-1, false);
  std::queue<point<int>> q;
  int x = std::lower_bound(xs.begin(), xs.end(), 0) - xs.begin() - 1;
  int y = std::lower_bound(ys.begin(), ys.end(), 0) - ys.begin() - 1;
  x = x*2 + 1; y = y*2 + 1;
  q.emplace(x, y);
  move4<int> m4;
  while(!q.empty()) {
    auto const& p = q.front(); q.pop();
    if(visited_xy[p.x/2][p.y/2]) continue;
    visited_xy[p.x/2][p.y/2] = true;
    m4.go(p);
    for(auto const& p: m4.res) {
      auto const& jp = p.first;
      if(w_xy[jp.x][jp.y] > 0) continue;
      auto const& np = p.second;
      if(np.x < 0 || np.x > 2*(XS-1) || np.y < 0 || np.y > 2*(YS-1)) fin("INF");
      if(!visited_xy[np.x/2][np.y/2]) q.push(np);
    }
  }
  // calc area
  int64_t ans = 0;
  for(int y = 0; y < YS-1; ++y) for(int x = 0; x < XS-1; ++x) if(visited_xy[x][y]) {
    ans += (int64_t)(xs[x+1] - xs[x])*(ys[y+1] - ys[y]);
  }
  fin(ans);
  return 0;
}


Measured memory_bytes: 19516