#![allow(
    non_snake_case,
    unused_variables,
    unused_assignments,
    unused_mut,
    unused_imports,
    dead_code
)]
//use proconio::fastout;
use proconio::input;
use proconio::marker::*;
use std::cmp::*;
use std::collections::*;
use std::ops::Bound::Included;
//use std::collections::VecDeque;

const MOD: i64 = 1_000_000_007;
fn main() {
    input! {
       N:usize,M:usize,
       mut ABC:[(i64,i64,i64);N],
       mut DEF:[(i64,i64,i64);M]
    }
    let inf = std::i64::MAX / 2;
    //ABC.sort_by_key(|&(_, _, c)| c);
    //DEF.sort_by_key(|&(d, _, _)| d);
    // 壁の数は高々1000個なので、先に座標を圧縮する。
    let mut xmap = BTreeMap::new();
    let mut ymap = BTreeMap::new();
    xmap.insert(0, 0);
    ymap.insert(0, 0);
    for &(a, b, c) in ABC.iter() {
        xmap.insert(a, 0);
        xmap.insert(b, 0);
        ymap.insert(c, 0);
    }
    for &(d, e, f) in DEF.iter() {
        xmap.insert(d, 0);
        ymap.insert(e, 0);
        ymap.insert(f, 0);
    }
    let mut xwidth = vec![0; xmap.len() * 2 + 1];
    let mut ywidth = vec![0; ymap.len() * 2 + 1];
    let mut prev = 0;
    // xwidth[0],ywidth[0]の幅がおかしくなるけどどうせアクセスしないので気にしない。
    for (i, (&k, _)) in xmap.clone().iter().enumerate() {
        xmap.insert(k, i * 2 + 1);
        xwidth[i * 2] = k - prev;
        prev = k;
    }
    for (i, (&k, _)) in ymap.clone().iter().enumerate() {
        ymap.insert(k, i * 2 + 1);
        ywidth[i * 2] = k - prev;
        prev = k;
    }
    let mut p = vec![vec![false; ymap.len() * 2 + 1]; xmap.len() * 2 + 1];
    for &(a, b, c) in ABC.iter() {
        let x1 = *xmap.get(&a).unwrap();
        let x2 = *xmap.get(&b).unwrap();
        let y = *ymap.get(&c).unwrap();
        for x in x1..=x2 {
            p[x][y] = true;
        }
    }
    for &(d, e, f) in DEF.iter() {
        let x = *xmap.get(&d).unwrap();
        let y1 = *ymap.get(&e).unwrap();
        let y2 = *ymap.get(&f).unwrap();
        for y in y1..=y2 {
            p[x][y] = true;
        }
    }
    // start位置を設定。
    // 移動候補をheapに追加していく。
    // println!("{:?}", p);
    let x = *xmap.get(&0).unwrap();
    let y = *ymap.get(&0).unwrap();
    let mut h = BinaryHeap::new();
    h.push((x - 1, y - 1));
    h.push((x - 1, y + 1));
    h.push((x + 1, y - 1));
    h.push((x + 1, y + 1));
    p[x - 1][y - 1] = true;
    p[x - 1][y + 1] = true;
    p[x + 1][y - 1] = true;
    p[x + 1][y + 1] = true;
    let mut ans = 0;
    //println!("xmap={:?},ymap={:?}", xmap, ymap);
    while h.len() > 0 {
        let (hx, hy) = h.pop().unwrap();
        if hx == 0 || hy == 0 || hx == xmap.len() * 2 || hy == ymap.len() * 2 {
            println!("INF");
            return;
        }
        // 領域の面積を加算。
        //println!("{:?}", h);
        //println!("{},{}", hx, hy);
        ans += xwidth[hx] * ywidth[hy];
        //移動する方向に壁が無く、かつ移動先でもないなら、heapに積む。
        if !p[hx - 1][hy] && !p[hx - 2][hy] {
            h.push((hx - 2, hy));
            p[hx - 2][hy] = true;
        }
        if !p[hx + 1][hy] && !p[hx + 2][hy] {
            h.push((hx + 2, hy));
            p[hx + 2][hy] = true;
        }
        if !p[hx][hy - 1] && !p[hx][hy - 2] {
            h.push((hx, hy - 2));
            p[hx][hy - 2] = true;
        }
        if !p[hx][hy + 1] && !p[hx][hy + 2] {
            h.push((hx, hy + 2));
            p[hx][hy + 2] = true;
        }
    }
    //println!("{:?}", p);
    println!("{}", ans);
}


Measured memory_bytes: 38236