fn main() {
	let mut s = String::new();
	use std::io::Read;
	std::io::stdin().read_to_string(&mut s).unwrap();
	let mut s = s.split_whitespace();
	let n: usize = s.next().unwrap().parse().unwrap();
	let m: usize = s.next().unwrap().parse().unwrap();
	let mut xs = vec![];
	let mut ys = vec![];
	let mut vert = vec![];
	let mut horz = vec![];
	for _ in 0..n {
		let y0: i32 = s.next().unwrap().parse().unwrap();
		let y1: i32 = s.next().unwrap().parse().unwrap();
		let x: i32 = s.next().unwrap().parse().unwrap();
		vert.push((y0, y1, x));
		xs.push(x);
		ys.push(y0);
		ys.push(y1);
	}
	for _ in 0..m {
		let y: i32 = s.next().unwrap().parse().unwrap();
		let x0: i32 = s.next().unwrap().parse().unwrap();
		let x1: i32 = s.next().unwrap().parse().unwrap();
		horz.push((y, x0, x1));
		xs.push(x0);
		xs.push(x1);
		ys.push(y);
	}
	xs.sort();
	xs.dedup();
	ys.sort();
	ys.dedup();
	let mut field = vec![vec![false; xs.len() + 1]; ys.len() + 1];
	let mut fence = vec![vec![0u8; xs.len() + 1]; ys.len() + 1];
	for (y0, y1, x) in vert.iter() {
		let yl = ys.binary_search(y0).unwrap() + 1;
		let yr = ys.binary_search(y1).unwrap();
		let x = xs.binary_search(x).unwrap();
		for y in yl..=yr {
			fence[y][x] |= 2;
			fence[y][x + 1] |= 8;
		}
	}
	for (y, x0, x1) in horz.iter() {
		let xl = xs.binary_search(x0).unwrap() + 1;
		let xr = xs.binary_search(x1).unwrap();
		let y = ys.binary_search(y).unwrap();
		for x in xl..=xr {
			fence[y][x] |= 4;
			fence[y + 1][x] |= 1;
		}
	}

	let mut q = vec![];
	let ystart = ys.lower_bound(&0) + 1;
	let xstart = xs.lower_bound(&0) + 1;

	q.push((ystart as i32, xstart as i32));
	while let Some((y, x)) = q.pop() {
		field[y as usize][x as usize] = true;
		for (i, (dy, dx)) in [(-1, 0), (0, 1), (1, 0), (0, -1)].iter().enumerate() {
			let ny = y + dy;
			let nx = x + dx;
			if ny >= 0
				&& ny <= ys.len() as i32
				&& nx >= 0 && nx <= xs.len() as i32
				&& fence[y as usize][x as usize] & (1 << i) == 0
				&& !field[ny as usize][nx as usize]
			{
				q.push((ny, nx));
			}
		}
	}
	let mut ans = 0i64;
	for y in 0..=ys.len() {
		for x in 0..=xs.len() {
			if field[y][x] {
				ans = ans.saturating_add(if y == 0 || y == ys.len() || x == 0 || x == xs.len() {
					std::i64::MAX
				} else {
					let h = ys[y] as i64 - ys[y - 1] as i64;
					let w = xs[x] as i64 - xs[x - 1] as i64;
					h * w
				});
			}
		}
	}
	if ans == std::i64::MAX {
		println!("INF");
	} else {
		println!("{}", ans);
	}
}

pub trait BinarySearch<'a, T: 'a> {
	fn lower_bound(&self, x: &T) -> usize;
}

impl<'a, T: 'a + Ord> BinarySearch<'a, T> for [T] {
	fn lower_bound(&self, x: &T) -> usize {
		let mut first = 0;
		let mut len = self.len() - first;
		while len > 0 {
			let half = len >> 1;
			let mid = first + half;
			use std::cmp::Ordering;
			match self[mid].cmp(x) {
				Ordering::Less => {
					first = mid + 1;
					len = len - half - 1;
				}
				Ordering::Equal | Ordering::Greater => {
					len = half;
				}
			}
		}
		first
	}
}
