#include <bits/stdc++.h>
#ifdef LOCAL_DEBUG
#define DEBUG 1
#define CERR if(DEBUG) cerr
#define MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,NAME,...) NAME
#define pr(...) CERR<<MACRO(__VA_ARGS__,pr10,pr9,pr8,pr7,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__)<<endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
#define pr9(a,b,c,d,e,f,g,h,i) pr1(a)<<pr8(b,c,d,e,f,g,h,i)
#define pr10(a,b,c,d,e,f,g,h,i,j) pr1(a)<<pr9(b,c,d,e,f,g,h,i,j)
#define prArr(a){CERR<<(#a)<<"={";int i=0;for(auto t:(a))CERR<<(i++?", ":"")<<t;CERR<<"}"<<endl;}
#else
#define DEBUG 0
#define pr(...)
#define prArr(a)
#endif
using namespace std;
using Int = long long;
using _int = int;
using ll = long long;
using Double = long double;
const Int INF = (1LL<<60)+1e9; // ~ 1.15 * 1e18
const Int mod = (1e9)+7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int,Int>;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
template<class T1, class T2> ostream& operator<<(ostream& o,pair<T1,T2> p){return o<<"("<<p.first<<","<<p.second<<")";}
template<class T1, class T2, class T3> ostream& operator<<(ostream& o,tuple<T1,T2,T3> t){return o<<"("<<get<0>(t)<<","<<get<1>(t)<<","<<get<2>(t)<<")";}
template<class T1, class T2> istream& operator>>(istream& i,pair<T1,T2> &p){return i>>p.first>>p.second;}
template<class T> ostream& operator<<(ostream& o,vector<T> a){Int i=0;for(T t:a)o<<(i++?" ":"")<<t;return o;}
template<class T> istream& operator>>(istream& i,vector<T> &a){for(T &t:a)i>>t;return i;}
//INSERT ABOVE HERE


template <typename T>
class Compress{
public:
  vector<T> X;
  bool ok;
  Compress():ok(false){};

  Int size(){assert(ok); return X.size();}
  void add(T a){ok = false; X.push_back(a); X.push_back(a-1); X.push_back(a+1);}
  //void add(T a){ok = false; X.push_back(a);}// X.push_back(a-1); X.push_back(a+1);}
  void add(const vector<T> a){for(T x:a) add(x);}
  //void add(const vector<T> &a){for(T x:a) add(x);}

  void build(){
    ok = true;
    sort(X.begin(),X.end());
    X.erase(unique(X.begin(),X.end()),X.end());
  }

  Int getL(T x){assert(ok); return lower_bound(X.begin(),X.end(),x) - X.begin();}
  Int getU(T x){assert(ok); return upper_bound(X.begin(),X.end(),x) - X.begin();}
};


signed main(){
  srand((unsigned)time(NULL));
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);

  Int N, M;
  cin>>N>>M;
  using PP = pair<P, P>;
  vector<PP> A;

  Compress<Int> X, Y;
  Int T = 2;
  for(Int i=0;i<N;i++){
    Int a, b, c;
    cin>>a>>b>>c; a *= T, b *= T, c *= T;
    A.push_back(PP(P(a, c), P(b, c)));
    X.add(a);
    X.add(b);
    Y.add(c);
  }

  for(Int i=0;i<M;i++){
    Int d, e, f;
    cin>>d>>e>>f; d *= T, e *= T, f *= T;
    A.push_back(PP(P(d, e), P(d, f)));
    X.add(d);
    Y.add(e);
    Y.add(f);
  }
  X.add(-INF);
  X.add(INF);
  Y.add(-INF);
  Y.add(INF);

  X.build();
  Y.build();
  auto get=[&](Int x, Int y){return P(X.getL(x), Y.getL(y));};


  Int H = Y.size();
  Int W = X.size();
  vector<vector<char> > mp1(Y.size()+1, vector<char>(X.size()+1,0));
  vector<vector<char> > mp2(Y.size()+1, vector<char>(X.size()+1,0));
  for(auto v:A){
    Int x, y; tie(x, y) = v.first;
    Int a, b; tie(a, b) = v.second;
    tie(x, y) = get(x, y);
    tie(a, b) = get(a, b);
    if(x != a && y == b){
      assert(x < a);
      mp1[y][x]++;
      mp1[y][a+1]--;
    }
    if(x == a && y != b){
      assert(y < b);
      mp2[y][x]++;
      mp2[b+1][x]--;
    }
  }

  for(Int i=0;i<=H;i++)
    for(Int j=1;j<W;j++) mp1[i][j] += mp1[i][j-1];

  for(Int i=0;i<=W;i++)
    for(Int j=1;j<H;j++) mp2[j][i] += mp2[j-1][i];

  Int ox, oy; tie(ox, oy) = get(0, 0);
  //mp[oy][ox] = 5;
  //for(Int i=0;i<H;i++) pr(mp[i]);
  //mp[oy][ox] = 0;

  vector<vector<char> > visited(Y.size(), vector<char>(X.size(),0));
  queue<P> Q;
  Q.push(P(ox, oy));
  visited[oy][ox] = 1;
  __int128_t ans = 0;
  while(!Q.empty()){
    Int x, y; tie(x, y) = Q.front(); Q.pop();
    //if(visited[y][x]) continue;
    //visited[y][x] = 1;
    {
      __int128_t a = X.X[x+1] - X.X[x];
      __int128_t b = Y.X[y+1] - Y.X[y];
      ans += a * b;
    }

    const Int dx[] = {0, 0, 1, -1};
    const Int dy[] = {1, -1, 0, 0};
    for(Int i=0;i<4;i++){
      if(mp1[y][x] && (i == 0 || i == 1)) continue; //横線に対して縦に移動しない
      if(mp2[y][x] && (i == 2 || i == 3)) continue; //縦線に対して横に移動しない
      Int nx = x + dx[i];
      Int ny = y + dy[i];
      if(nx < 0 || ny < 0 || nx >= W || ny >= H) continue;
      if(visited[ny][nx]) continue;
      if(i == 2 && (mp2[ny][nx])) continue; //右にいくときに縦線
      if(i == 0 && (mp1[ny][nx])) continue; //下にいくときに横線
      visited[ny][nx] = 1;
      Q.push(P(nx, ny));
    }
  }

  if(visited[0][0] || visited[H-1][0] || visited[0][W-1] || visited[H-1][W-1]){
    cout<<"INF"<<endl;
    return 0;
  }
  assert(ans % (T * T) == 0);
  ans /= T * T;
  cout<<(Int)ans<<endl;

  return 0;
}


Measured memory_bytes: 242316