#include<bits/stdc++.h>
using namespace std;using ll=long long;using vi=vector<int>;using vvi=vector<vi>;using vl=vector<ll>;using vvl=vector<vl>;using P=pair<int,int>;using PL=pair<ll,ll>;using vp=vector<P>;using vpl=vector<PL>;
#define pqueue priority_queue
template<typename T>constexpr auto inf=numeric_limits<T>::max()/2;constexpr int INF=inf<int>,MOD=1000000007;constexpr ll LINF=inf<ll>;
#define _ol3(_1,_2,_3,name,...)name
#define _rep(i,n)_repi(i,0,n)
#define _repi(i,a,b)for(int i=a,i##_l=(b);i<i##_l;++i)
#define REP(...)_ol3(__VA_ARGS__,_repi,_rep,)(__VA_ARGS__)
#define REPR(i,n)for(int i=n-1;i>=0;--i)
#define REPA(i,v)REP(i,(v).size())
#define all(v)(v).begin(),(v).end()
#define rall(v)(v).rbegin(),(v).rend()
#define bit(n)(1ll<<(n))
#define F first
#define S second
#define endl '\n'
void _print(ostream&){}template<class T,class...U>void _print(ostream&s,const T&t,const U&...u){s<<t<<(sizeof...(u)?' ':'\n');_print(s,u...);}
template<class...T>void print(const T&...t){_print(cout,t...);}template<class...T>void dprint(const T&...t){_print(cerr,t...);}
#ifndef LOCAL
struct osd{template<class T>osd&operator<<(const T&t){return*this;}};osd cer_;
#define dprint(...)
#define cerr cer_
#endif
#define dbg(x) dprint("@l",__LINE__,':',#x,'=',x)
#define cho(n,a,b)print((n)?a:b)
void YES(int n){cho(n,"YES","NO");}void Yes(int n){cho(n,"Yes","No");}void Poss(int n){cho(n,"Possible","Impossible");}
template<class T, class U>bool chmax(T&a,const U&b){bool x=a<b;x?a=b:b;return x;}template<class T, class U>bool chmin(T&a,const U&b){bool x=a>b;x?a=b:b;return x;}
template<class T, class U>auto max(const T&a,const U&b){return a<b?b:a;}template<class T, class U>auto min(const T&a,const U&b){return a<b?a:b;}
template<class T,class U>ostream&operator<<(ostream&o,const pair<T,U>&p){return o<<p.F<<' '<<p.S;}template<class T,class U>istream&operator>>(istream&i,pair<T,U>&p){return i>>p.F>>p.S;}
template<class T>class iterable{static false_type c(string v);template<class U>static auto c(U v)->decltype(all(v),true_type());static false_type c(...);public:const static bool value=decltype(c(declval<T>()))::value;};
template<class T,enable_if_t<iterable<T>::value,int> =0>ostream&operator<<(ostream&o,const T&v){for(auto&&i:v)o<<i<<' ';return o;}
template<class T>istream&operator>>(istream&i,vector<T>&v){for(T&j:v)i>>j;return i;}template<class T>vector<T>&operator<<(vector<T>&v,const T&t){v.push_back(t);return v;}
template<class T,class U>queue<T,U>&operator<<(queue<T,U>&v, const T&t){v.push(t);return v;}template<class T,class U>queue<T,U>&operator>>(queue<T,U>&v, T&t){t=v.front();v.pop();return v;}
template<class T,class U,class V>pqueue<T,U,V>&operator<<(pqueue<T,U,V>&v, const T&t){v.push(t);return v;}template<class T,class U,class V>pqueue<T,U,V>&operator>>(pqueue<T,U,V>&v, T&t){t=v.front();v.pop();return v;}
template<class T,class U>stack<T,U>&operator<<(stack<T,U>&v, const T&t){v.push(t);return v;}template<class T,class U>stack<T,U>&operator>>(stack<T,U>&v, T&t){t=v.front();v.pop();return v;}
template<class T,class U,class V>set<T,U,V>&operator<<(set<T,U,V>&v,const T&t){v.insert(t);return v;}template<class T,class U,class V>multiset<T,U,V>&operator<<(multiset<T,U,V>&v,const T&t){v.insert(t);return v;}
template<class T,enable_if_t<is_integral<T>::value,int> =0>T mod(T a, T b){if(a>0)return a%b;return b-(-a%b);}template<class T,enable_if_t<is_floating_point<T>::value,int> =0>T mod(T a, T b){if(a>0)return fmod(a,b);return b-fmod(-a,b);}
template<class T,class U>pair<T,U>&operator+=(pair<T,U>&a, const pair<T,U>&b){a.F+=b.F;a.S+=b.S;return a;}template<class T,class U>pair<T,U> operator+(const pair<T,U>&a, const pair<T,U>&b){auto r=a;return r+=b;}
template<class T,class U>pair<T,U>&operator-=(pair<T,U>&a, const pair<T,U>&b){a.F-=b.F;a.S-=b.S;return a;}template<class T,class U>pair<T,U> operator-(const pair<T,U>&a, const pair<T,U>&b){auto r=a;return r-=b;}
template<class T,class U>pair<T,U> operator-(const pair<T,U>&a){return {-a.F, -a.S};}
template<class T,class U>double norm(const pair<T,U>&p){return norm(p.F)+norm(p.S);}template<class T,class U>double abs(const pair<T,U>&p){return sqrt(norm(p));}
class UnionFind{
private:
    vi data;
public:
    UnionFind(int size):data(size,-1){}
    bool unite(int x,int y){
        dprint(x,y);
        x=root(x);y=root(y);
        if(x!=y){
            if(data[y]<data[x])swap(x,y);
            data[x]+=data[y];data[y]=x;
        }
        return x!=y;
    }
    bool find(int x,int y){
        return root(x)==root(y);
    }
    int root(int x){
        return data[x]<0?x:data[x]=root(data[x]);
    }
    int size(int x){
        return -data[root(x)];
    }
};
int main(){
    cin.tie(0);ios::sync_with_stdio(0);
    cout<<fixed<<setprecision(10);

    int n,m;
    cin>>n>>m;
    if(!n || !m){
        cout<<"INF";
        return 0;
    }
    vector<pair<P, int>> xl(n);
    vector<pair<int, P>> yl(m);
    cin>>xl>>yl;
    
    vi xs, ys;
    xs<<0;ys<<0;
    REP(i,n) ys<<xl[i].S;
    REP(i,m) xs<<yl[i].F;
    sort(all(xs));xs.erase(unique(all(xs)),xs.end());
    sort(all(ys));ys.erase(unique(all(ys)),ys.end());

    REP(i,n){
        xl[i].S = lower_bound(all(ys), xl[i].S) - ys.begin();
        xl[i].F.F = lower_bound(all(xs), xl[i].F.F) - xs.begin();
        xl[i].F.S = upper_bound(all(xs), xl[i].F.S) - xs.begin() - 1;
        if(xl[i].F.F > xl[i].F.S) xl[i].F.S = xl[i].F.F;
    }
    
    REP(i,m){
        yl[i].F = lower_bound(all(xs), yl[i].F) - xs.begin();
        yl[i].S.F = lower_bound(all(ys), yl[i].S.F) - ys.begin();
        yl[i].S.S = upper_bound(all(ys), yl[i].S.S) - ys.begin() - 1;
        if(yl[i].S.F > yl[i].S.S) yl[i].S.S = yl[i].S.F;
    }

    dbg(xs);
    dbg(ys);
    
    
    const int h = ys.size() - 1;
    const int w = xs.size() - 1;
    
    
    vvi xls(h+1, vi(w+1 + 1)); // 横の線分についてのいもすもどき
    vvi yls(w+1, vi(h+1 + 1));
    REP(i,n) {
        auto& ref = xls[xl[i].S];
        // dprint(xl[i].F);
        ref[xl[i].F.F] ++;
        ref[xl[i].F.S] --;
    }
    REP(i,m) {
        auto& ref = yls[yl[i].F];
        // if(yl[i].F==2)dbg(yl[i]);
        ref[yl[i].S.F] ++;
        ref[yl[i].S.S] --;
    }


    UnionFind uf(h*w + 1);
    int cs;
    dprint("16 16 1");
    REP(i,h-1) {
        cs = 0;
        REP(j,w) {
            cs += xls[i+1][j];
            if(!cs) {
                uf.unite(i*w+j, (i+1)*w+j);
            }
        }
    }

    // top
    dprint("16 16 2");
    cs = 0;
    REP(j,w) {
        cs += xls[0][j];
        if(!cs) {
            uf.unite(0*w+j, h*w);
        }
    }
    // bottom
    dprint("16 16 3");
    cs = 0;
    REP(j,w) {
        cs += xls[h][j];
        if(!cs) {
            uf.unite((h-1)*w+j, h*w);
        }
    }

    dprint("16 16 4");
    REP(j,w-1) {
        cs = 0;
        REP(i,h) {
            cs += yls[j+1][i];
            if(!cs) {
                uf.unite(i*w+j, i*w+(j+1));
            }
        }
    }
    
    // left
    dprint("16 16 5");
    cs = 0;
    REP(i,h) {
        cs += yls[0][i];
        if(!cs) {
            uf.unite(i*w+0, h*w);
        }
    }
    // right
    dprint("16 16 6");
    cs = 0;
    REP(i,h) {
        cs += yls[w][i];
        if(!cs) {
            uf.unite(i*w+(w-1), h*w);
        }
    }

    int zx = lower_bound(all(xs), 0) - xs.begin();
    int zy = lower_bound(all(ys), 0) - ys.begin();

    if(uf.find(zy*w + zx, h*w)) {
        cout<<"INF";
        return 0;
    }
    ll ans=0;
    REP(i,w)REP(j,h){
        if(uf.find(zy*w+zx, j*w+i)) {
            ans += (ll)(xs[i+1] - xs[i]) * (ys[j+1] - ys[j]);
        }
    }
    cout<<ans<<endl;
}
