#include <bits/stdc++.h>
using namespace std;
using namespace placeholders;
using LL = long long;
using ULL = unsigned long long;
using VI = vector<int>;
using VVI = vector<vector<int> >;
using VS = vector<string>;
using ISS = istringstream;
using OSS = ostringstream;
using PII = pair<int, int>;
using VPII = vector<pair<int, int> >;
template <typename T = int>
using VT = vector<T>;
template <typename T = int>
using VVT = vector<vector<T> >;
template <typename T = int>
using LIM = numeric_limits<T>;
template <typename T = int>
using OSI = ostream_iterator<T>;
template <typename T>
inline istream &operator>>(istream &s, vector<T> &v) {
  for (T &t : v) {
    s >> t;
  }
  return s;
}
template <typename T>
inline ostream &operator<<(ostream &s, const vector<T> &v) {
  for (int i = 0; i < int(v.size()); ++i) {
    s << (" " + !i) << v[i];
  }
  return s;
}
void in_impl(){};
template <typename T, typename... TS>
void in_impl(T &head, TS &...tail) {
  cin >> head;
  in_impl(tail...);
}
template <typename T>
inline T fromString(const string &s) {
  T res;
  istringstream iss(s);
  iss >> res;
  return res;
}
template <typename T>
inline string toString(const T &a) {
  ostringstream oss;
  oss << a;
  return oss.str();
}
template <typename T>
inline bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
inline bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
constexpr auto INF = LIM<>::max() / 2;
class DisjointSetForest {
 private:
  const int N;
  vector<int> parent;
  vector<int> rank;
  int groups_;
  std::vector<int> sizes;

 public:
  DisjointSetForest(int n)
      : N(n), parent(N), rank(N, 0), groups_(N), sizes(N, 1) {
    std::iota(parent.begin(), parent.end(), 0);
    return;
  }
  int find(int x) {
    if (parent[x] == x) {
      return x;
    }
    return parent[x] = find(parent[x]);
  }
  bool same(int x, int y) { return find(x) == find(y); }
  bool unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return false;
    }
    if (rank[x] < rank[y]) {
      parent[x] = y;
      sizes[y] += sizes[x];
    } else {
      parent[y] = x;
      sizes[x] += sizes[y];
      if (rank[x] == rank[y]) {
        ++rank[x];
      }
    }
    --groups_;
    return true;
  }
  int groups() const { return groups_; }
  int groupSize(const int x) { return sizes[find(x)]; }
};
VI compress(const VI &a, const VI &b, const VI &c) {
  VI res{-INF, 0, INF};
  copy(begin(a), end(a), back_inserter(res));
  copy(begin(b), end(b), back_inserter(res));
  copy(begin(c), end(c), back_inserter(res));
  sort(begin(res), end(res));
  res.erase(unique(begin(res), end(res)), end(res));
  return res;
}
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << setprecision(12) << fixed;
  int N, M;
  in_impl(N, M);
  ;
  VI A(N), B(N), C(N), D(M), E(M), F(M);
  for (int i = (int)(0); i < (int)(N); ++i) {
    cin >> A[i] >> B[i] >> C[i];
  }
  for (int i = (int)(0); i < (int)(M); ++i) {
    cin >> D[i] >> E[i] >> F[i];
  }
  const VI ys = compress(A, B, D);
  const VI xs = compress(C, E, F);
  const int H = ((int)(ys).size());
  const int W = ((int)(xs).size());
  VVI right_bounded(H, VI(W)), down_bounded(H, VI(W));
  for (int i = (int)(0); i < (int)(N); ++i) {
    const int idx_x = --lower_bound(begin(xs), end(xs), C[i]) - begin(xs);
    const int idx_y1 = lower_bound(begin(ys), end(ys), A[i]) - begin(ys);
    const int idx_y2 = lower_bound(begin(ys), end(ys), B[i]) - begin(ys);
    for (int j = (int)(idx_y1); j < (int)(idx_y2); ++j) {
      right_bounded[j][idx_x] = true;
    }
  }
  for (int i = (int)(0); i < (int)(M); ++i) {
    const int idx_y = --lower_bound(begin(ys), end(ys), D[i]) - begin(ys);
    const int idx_x1 = lower_bound(begin(xs), end(xs), E[i]) - begin(xs);
    const int idx_x2 = lower_bound(begin(xs), end(xs), F[i]) - begin(xs);
    for (int j = (int)(idx_x1); j < (int)(idx_x2); ++j) {
      down_bounded[idx_y][j] = true;
    }
  }
  DisjointSetForest dsf(H * W);
  const auto grid_id = [&](const int y, const int x) { return y * W + x; };
  for (int i = (int)(0); i < (int)(H); ++i) {
    for (int j = (int)(0); j < (int)(W); ++j) {
      if (i + 1 < H && !down_bounded[i][j]) {
        dsf.unite(grid_id(i, j), grid_id(i + 1, j));
      }
      if (j + 1 < W && !right_bounded[i][j]) {
        dsf.unite(grid_id(i, j), grid_id(i, j + 1));
      }
    }
  }
  const int idx_y0 = lower_bound(begin(ys), end(ys), 0) - begin(ys);
  const int idx_x0 = lower_bound(begin(xs), end(xs), 0) - begin(xs);
  if (dsf.same(0, grid_id(idx_y0, idx_x0))) {
    cout << "INF" << endl;
    return 0;
  }
  int res = 0;
  for (int i = (int)(0); i < (int)(H); ++i) {
    for (int j = (int)(0); j < (int)(W); ++j) {
      if (!dsf.same(grid_id(i, j), grid_id(idx_y0, idx_x0))) {
        continue;
      }
      const LL dy = ys[i + 1] - ys[i];
      const LL dx = xs[j + 1] - xs[j];
      res += dy * dx;
    }
  }
  cout << res << endl;
  return 0;
}
