#include <algorithm>
#include <array>
#include <iomanip>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>

const std::array<int32_t, 4> dx{-1, 0, 1, 0};
const std::array<int32_t, 4> dy{0, -1, 0, 1};

class DSF {
 private:
  uint64_t groups;
  std::vector<int64_t> forest, rank;

  uint64_t root(uint64_t x) {
    return (forest[x] < 0) ? x : forest[x] = root(forest[x]);
  }

 public:
  DSF(int64_t s) : groups(s), forest(s, -1), rank(s, 0) {}

  bool judge(uint64_t x, uint64_t y) { return root(x) == root(y); }
  uint64_t count_groups() const { return groups; }
  uint64_t size(uint64_t x) { return -forest[root(x)]; }

  bool unite(uint64_t x, uint64_t y) {
    x = root(x), y = root(y);
    if (x == y) return false;

    groups--;
    if (rank[x] < rank[y]) std::swap(x, y);
    forest[x] += forest[y];
    forest[y] = x;
    if (rank[x] == rank[y]) rank[x]++;
    return true;
  }
};

inline uint32_t id(const std::vector<int32_t>& coord, int32_t target) {
  return std::lower_bound(coord.begin(), coord.end(), target) - coord.begin();
}

int main() {
  uint32_t N = 0, M = 0;
  std::cin >> N >> M;
  std::vector<int32_t> A(N), B(N), C(N);
  for (size_t n = 0; n < N; n++) std::cin >> A[n] >> B[n] >> C[n];
  std::vector<int32_t> D(M), E(M), F(M);
  for (size_t m = 0; m < M; m++) std::cin >> D[m] >> E[m] >> F[m];

  // coordinate compression
  std::vector<int32_t> x_mesh(A);
  x_mesh.insert(x_mesh.end(), B.begin(), B.end());
  x_mesh.insert(x_mesh.end(), D.begin(), D.end());
  x_mesh.push_back(0);
  std::vector<int32_t> y_mesh(C);
  y_mesh.insert(y_mesh.end(), E.begin(), E.end());
  y_mesh.insert(y_mesh.end(), F.begin(), F.end());
  y_mesh.push_back(0);

  std::sort(x_mesh.begin(), x_mesh.end());
  std::sort(y_mesh.begin(), y_mesh.end());

  x_mesh.erase(std::unique(x_mesh.begin(), x_mesh.end()), x_mesh.end());
  y_mesh.erase(std::unique(y_mesh.begin(), y_mesh.end()), y_mesh.end());

  // gen grid
  uint32_t X = x_mesh.size() + 1, Y = y_mesh.size() + 1;
  auto encode = [=](uint32_t x, uint32_t y) { return Y * x + y; };
  std::vector<bool> V_wall(X * Y, false);
  for (size_t n = 0; n < N; n++) {
    uint32_t A_id = id(x_mesh, A[n]), B_id = id(x_mesh, B[n]),
             C_id = id(y_mesh, C[n]);
    for (size_t i = A_id; i < B_id; i++) V_wall[encode(i + 1, C_id)] = true;
  }
  std::vector<bool> H_wall(X * Y, false);
  for (size_t m = 0; m < M; m++) {
    uint32_t D_id = id(x_mesh, D[m]), E_id = id(y_mesh, E[m]),
             F_id = id(y_mesh, F[m]);
    for (size_t i = E_id; i < F_id; i++) H_wall[encode(D_id, i + 1)] = true;
  }

  // union find
  DSF uf(X * Y);
  for (size_t i = 0; i < X; i++) {
    for (size_t j = 0; j < Y; j++) {
      uint64_t enc = encode(i, j);
      if (j + 1 < Y && !V_wall[enc]) uf.unite(enc, encode(i, j + 1));
      if (i + 1 < X && !H_wall[enc]) uf.unite(enc, encode(i + 1, j));
    }
  }

  uint64_t cow = encode(id(x_mesh, 0) + 1, id(y_mesh, 0) + 1);
  if (uf.judge(encode(0, 0), cow)) {
    std::cout << "INF" << std::endl;
  } else {
    uint64_t area = 0;
    for (size_t i = 1; i < X; i++) {
      for (size_t j = 1; j < Y; j++) {
        if (uf.judge(encode(i, j), cow)) {
          area += static_cast<uint64_t>(x_mesh[i] - x_mesh[i - 1]) *
                  static_cast<uint64_t>(y_mesh[j] - y_mesh[j - 1]);
        }
      }
    }
    std::cout << area << std::endl;
  }

  return 0;
}

Measured memory_bytes: 146292