use proconio::input;
use std::collections::BTreeMap;

fn merge_lines(l : &Vec<(i64, (i64, i64))>) -> Vec<(i64, (i64, i64))> {
    let mut res = Vec::new();
    let mut s = None;
    for i in 0..l.len() {
        if s == None { s = Some(l[i]) }
        let mut c = s.unwrap();
        if i == l.len() - 1 || c.0 != l[i+1].0 || (c.1).1 < (l[i+1].1).0 {
            res.push(c);
            s = None
        } else {
            (c.1).1 = (c.1).1.max((l[i+1].1).1);
            s = Some(c);
        }
    }
    res
}

fn dir(prev : (i64, i64), cur : (i64, i64), next : (i64, i64)) -> i32 {
    let x1 = cur.0 - prev.0;
    let y1 = cur.1 - prev.1;
    let x2 = next.0 - cur.0;
    let y2 = next.1 - cur.1;
    let cr = x1 * y2 - x2 * y1;
    if cr > 0 { 0 }
    else if cr < 0 { 2 }
    else if x1 * x2 + y1 * y2 > 0 { 1 }
    else { 3 }
}

fn main() {
    input! {
        n : usize,
        m : usize,
        vin : [((i64, i64), i64); n],
        mut h : [(i64, (i64, i64)); m]
    }
    let mut v = vin.iter().map(|&t| (t.1, t.0)).collect::<Vec<_>>();
    v.sort();
    h.sort();
    let vl = merge_lines(&v);
    let hl = merge_lines(&h);
    let mut pts = Vec::new();
    let mut vtx_v = vec![Vec::new(); vl.len()];
    let mut vtx_h = vec![Vec::new(); hl.len()];
    for i in 0..vl.len() {
        pts.push(((vl[i].1).0, vl[i].0));
        pts.push(((vl[i].1).1, vl[i].0));
        vtx_v[i].push(((vl[i].1).0, vl[i].0));
        vtx_v[i].push(((vl[i].1).1, vl[i].0));
    }
    for j in 0..hl.len() {
        pts.push((hl[j].0, (hl[j].1).0));
        pts.push((hl[j].0, (hl[j].1).1));
        vtx_h[j].push((hl[j].0, (hl[j].1).0));
        vtx_h[j].push((hl[j].0, (hl[j].1).1));
        if (hl[j].1).0 <= 0 && 0 <= (hl[j].1).1 {
            pts.push((hl[j].0, 0));
            vtx_h[j].push((hl[j].0, 0));
        }
    }
    for i in 0..vl.len() {
        for j in 0..hl.len() {
            if (hl[j].1).0 <= vl[i].0 && vl[i].0 <= (hl[j].1).1 && (vl[i].1).0 <= hl[j].0 && hl[j].0 <= (vl[i].1).1 {
                pts.push((hl[j].0, vl[i].0));
                vtx_v[i].push((hl[j].0, vl[i].0));
                vtx_h[j].push((hl[j].0, vl[i].0));
            }
        }
    }
    pts.sort();
    pts.dedup();
    let mut idx = BTreeMap::<(i64, i64), usize>::new();
    for i in 0..pts.len() {
        idx.insert(pts[i], i);
    }
    let mut g = vec![Vec::new(); pts.len()];
    for t in &mut vtx_v {
        t.sort();
        t.dedup();
        for i in 0..t.len()-1 {
            let a = idx[&t[i]];
            let b = idx[&t[i+1]];
            g[a].push(b);
            g[b].push(a);
        }
    }
    for t in &mut vtx_h {
        t.sort();
        t.dedup();
        for i in 0..t.len()-1 {
            let a = idx[&t[i]];
            let b = idx[&t[i+1]];
            g[a].push(b);
            g[b].push(a);
        }
    }

    let mut res = i64::max_value();
    let mut checked = vec![0; pts.len()];
    for i in 0..pts.len() {
        if checked[i] == 1 { continue; }
        if pts[i].1 != 0 { continue; }
        if pts[i].0 < 0 { continue; }
        let mut pos = i;
        let mut prev = (pts[i].0, -1);
        let mut cur = pts[i];
        let mut area = 0;
        let mut first_dst = pts.len();
        loop {
            checked[pos] = 1;
            let mut next_idx = 0;
            let mut next_dir = 4;
            for &p in &g[pos] {
                let d = dir(prev, cur, pts[p]);
                if d < next_dir {
                    next_idx = p;
                    next_dir = d;
                }
            }
            if pos == i && next_idx == first_dst { break; }
            let next = pts[next_idx];
            area += cur.0 * next.1 - cur.1 * next.0;
            prev = cur;
            cur = next;
            pos = next_idx;
            if first_dst == pts.len() { first_dst = next_idx; }
        }
        if area > 0 { res = res.min(area); }
    }
    if res == i64::max_value() {
        println!("INF");
    } else {
        println!("{}", res/2);
    }
}
