Problem:
Score: 600 points

Problem Statement

There is a grass field that stretches infinitely.

In this field, there is a negligibly small cow. Let (x, y) denote the point that is x\ \mathrm{cm} south and y\ \mathrm{cm} east of the point where the cow stands now. The cow itself is standing at (0, 0).

There are also N north-south lines and M east-west lines drawn on the field. The i-th north-south line is the segment connecting the points (A_i, C_i) and (B_i, C_i), and the j-th east-west line is the segment connecting the points (D_j, E_j) and (D_j, F_j).

What is the area of the region the cow can reach when it can move around as long as it does not cross the segments (including the endpoints)? If this area is infinite, print INF instead.

Constraints

All values in input are integers between -10^9 and 10^9 (inclusive).

1 \leq N, M \leq 1000

A_i < B_i\ (1 \leq i \leq N)

E_j < F_j\ (1 \leq j \leq M)

The point (0, 0) does not lie on any of the given segments.

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1 C_1
:
A_N B_N C_N
D_1 E_1 F_1
:
D_M E_M F_M

Output

If the area of the region the cow can reach is infinite, print INF; otherwise, print an integer representing the area in \mathrm{cm^2}.

(Under the constraints, it can be proved that the area of the region is always an integer if it is not infinite.)

Sample Input 1

5 6
1 2 0
0 1 1
0 2 2
-3 4 -1
-2 6 3
1 0 1
0 1 2
2 0 2
-1 -4 5
3 -2 4
1 2 4

Sample Output 1

13

The area of the region the cow can reach is 13\ \mathrm{cm^2}.

Sample Input 2

6 1
-3 -1 -2
-3 -1 1
-2 -1 2
1 4 -2
1 4 -1
1 4 1
3 1 4

Sample Output 2

INF

The area of the region the cow can reach is infinite.

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Linq;

using E = System.Linq.Enumerable;

internal partial class Solver {
    public int[] Dx = new int[] { 0, 1, 0, -1 };
    public int[] Dy = new int[] { 1, 0, -1, 0 };
    public void Run() {
        var n = ni();
        var m = ni();
        var a = new int[n];
        var b = new int[n];
        var c = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = ni();
            b[i] = ni();
            c[i] = ni();
        }
        var d = new int[m];
        var e = new int[m];
        var f = new int[m];
        for (int i = 0; i < m; i++) {
            d[i] = ni();
            e[i] = ni();
            f[i] = ni();
        }
        var xs = c.Concat(e).Concat(f).Concat(new[] { 0 }).Distinct().OrderBy(x => x).ToArray();
        var ys = a.Concat(b).Concat(d).Concat(new[] { 0 }).Distinct().OrderBy(x => x).ToArray();

        var xsIndex = E.Range(0, xs.Length).ToDictionary(i => xs[i], i => i);
        var ysIndex = E.Range(0, ys.Length).ToDictionary(i => ys[i], i => i);

        var height = ys.Length * 2 - 1;
        var width = xs.Length * 2 - 1;
        var map = new char[height, width];
        var xWidth = new int[width];
        var yWidth = new int[height];

        for (int i = 0; i + 1 < xs.Length; i++) {
            xWidth[2 * i + 1] = xs[i + 1] - xs[i];
        }
        for (int i = 0; i + 1 < ys.Length; i++) {
            yWidth[2 * i + 1] = ys[i + 1] - ys[i];
        }
        for (int i = 0; i < n; i++) {
            var x = 2 * xsIndex[c[i]];
            var y1 = 2 * ysIndex[a[i]];
            var y2 = 2 * ysIndex[b[i]];
            for (int y = y1; y <= y2; y++) {
                map[y, x] = '#';
            }
        }
        for (int i = 0; i < m; i++) {
            var y = 2 * ysIndex[d[i]];
            var x1 = 2 * xsIndex[e[i]];
            var x2 = 2 * xsIndex[f[i]];
            for (int x = x1; x <= x2; x++) {
                map[y, x] = '#';
            }
        }
        long ans = 0;

        var sx = 2 * xsIndex[0];
        var sy = 2 * ysIndex[0];
        var queue = new FastQueue<(int, int)>(height * width * 2);
        queue.Enqueue((sx, sy));
        var visited = new bool[height, width];
        while (queue.Count > 0) {
            var (cx, cy) = queue.Dequeue();
            if (visited[cy, cx]) continue;
            visited[cy, cx] = true;
            ans += 1L * yWidth[cy] * xWidth[cx];
            for (int k = 0; k < 4; k++) {
                var nx = cx + Dx[k];
                var ny = cy + Dy[k];
                if (!((0 <= nx && nx < width) && (0 <= ny && ny < height))) {
                    ans = long.MaxValue;
                    break;
                }
                if (map[ny, nx] == '#' || visited[ny, nx]) continue;
                queue.Enqueue((nx, ny));
            }
            if (ans == long.MaxValue) break;
        }

        cout.WriteLine(ans == long.MaxValue ? "INF" : ans.ToString());
    }
}

public class FastQueue<T> {
    private T[] _array;
    private int _head;
    private int _tail;
    public int Count { get; private set; }

    public FastQueue(int capacity = 16) {
        _array = new T[capacity];
        _head = 0;
        _tail = 0;
    }

    public void Clear() {
        _head = _tail = Count = 0;
    }

    private void Expand() {
        var newarray = new T[_array.Length * 2];

        if (_head < _tail) {
            Array.Copy(_array, _head, newarray, 0, Count);
        } else {
            Array.Copy(_array, _head, newarray, 0, _array.Length - _head);
            Array.Copy(_array, 0, newarray, _array.Length - _head, _tail);
        }

        _head = 0;
        _tail = Count == newarray.Length ? 0 : Count;
        _array = newarray;
    }

    public void Enqueue(T value) {
        if (Count + 1 == _array.Length) { // expand
            Expand();
        }
        Count++;
        _array[_tail++] = value;
        if (_tail == _array.Length) {
            _tail = 0;
        }
    }

    public T Peek() {
        if (Count == 0) {
            throw new Exception("empty");
        }

        return _array[_head];
    }

    public T Dequeue() {
        if (Count == 0) {
            throw new Exception("empty");
        }

        var ret = _array[_head++];
        Count--;
        if (_head == _array.Length) {
            _head = 0;
        }
        return ret;
    }
}
// PREWRITEN CODE BEGINS FROM HERE
internal partial class Solver : Scanner {
    public static void Main() {
#if LOCAL
        byte[] inputBuffer = new byte[1000000];
        var inputStream = Console.OpenStandardInput(inputBuffer.Length);
        using (var reader = new StreamReader(inputStream, Console.InputEncoding, false, inputBuffer.Length)) {
            Console.SetIn(reader);
            new Solver(Console.In, Console.Out).Run();
        }
#else
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        new Solver(Console.In, Console.Out).Run();
        Console.Out.Flush();
#endif
    }

#pragma warning disable IDE0052
    private readonly TextReader cin;
    private readonly TextWriter cout;
#pragma warning restore IDE0052

    public Solver(TextReader reader, TextWriter writer)
        : base(reader) {
        cin = reader;
        cout = writer;
    }
    public Solver(string input, TextWriter writer)
        : this(new StringReader(input), writer) {
    }

#pragma warning disable IDE1006
#pragma warning disable IDE0051
    private int ni() { return NextInt(); }
    private int[] ni(int n) { return NextIntArray(n); }
    private long nl() { return NextLong(); }
    private long[] nl(int n) { return NextLongArray(n); }
    private double nd() { return NextDouble(); }
    private double[] nd(int n) { return NextDoubleArray(n); }
    private string ns() { return Next(); }
    private string[] ns(int n) { return NextArray(n); }
#pragma warning restore IDE1006
#pragma warning restore IDE0051
}

internal static class LinqPadExtension {
    [Conditional("DEBUG")]
    public static void Dump<T>(this T obj) {
#if DEBUG
        LINQPad.Extensions.Dump(obj);
#endif
    }
}

public class Scanner {
    private readonly TextReader Reader;
    private readonly CultureInfo ci = CultureInfo.InvariantCulture;

    private readonly char[] buffer = new char[2 * 1024];
    private int cursor = 0, length = 0;
    private string Token;
    private readonly StringBuilder sb = new StringBuilder(1024);

    public Scanner()
        : this(Console.In) {
    }

    public Scanner(TextReader reader) {
        Reader = reader;
    }

    public int NextInt() { return checked((int)NextLong()); }
    public long NextLong() {
        var s = Next();
        long r = 0;
        int i = 0;
        bool negative = false;
        if (s[i] == '-') {
            negative = true;
            i++;
        }
        for (; i < s.Length; i++) {
            r = r * 10 + (s[i] - '0');
#if DEBUG
            if (!char.IsDigit(s[i])) throw new FormatException();
#endif
        }
        return negative ? -r : r;
    }
    public double NextDouble() { return double.Parse(Next(), ci); }
    public string[] NextArray(int size) {
        string[] array = new string[size];
        for (int i = 0; i < size; i++) {
            array[i] = Next();
        }

        return array;
    }
    public int[] NextIntArray(int size) {
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextInt();
        }

        return array;
    }

    public long[] NextLongArray(int size) {
        long[] array = new long[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextLong();
        }

        return array;
    }

    public double[] NextDoubleArray(int size) {
        double[] array = new double[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextDouble();
        }

        return array;
    }

    public string Next() {
        if (Token == null) {
            if (!StockToken()) {
                throw new Exception();
            }
        }
        var token = Token;
        Token = null;
        return token;
    }

    public bool HasNext() {
        if (Token != null) {
            return true;
        }

        return StockToken();
    }

    private bool StockToken() {
        while (true) {
            sb.Clear();
            while (true) {
                if (cursor >= length) {
                    cursor = 0;
                    if ((length = Reader.Read(buffer, 0, buffer.Length)) <= 0) {
                        break;
                    }
                }
                var c = buffer[cursor++];
                if (33 <= c && c <= 126) {
                    sb.Append(c);
                } else {
                    if (sb.Length > 0) break;
                }
            }

            if (sb.Length > 0) {
                Token = sb.ToString();
                return true;
            }

            return false;
        }
    }
}