#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include "testlib.h"

using namespace std;
using namespace __gnu_pbds;

using ll = long long;
using pii = pair<int, int>;

template <typename T>
using oset = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define all(x) x.begin(), x.end()

struct query {
    int t, x, y;
};

struct Testcase {
    int n, m;
    vector<pii> a, b;
    int q;
    vector<query> queries;
};

ostream& operator<<(ostream& out, const Testcase &t) {
    out << t.n << ' ' << t.m << '\n';
    for (auto [x, y] : t.a)
        out << x << ' ' << y << '\n';
    for (auto [x, y] : t.b)
        out << x << ' ' << y << '\n';
    out << t.q << '\n';
    for (auto [type, x, y] : t.queries)
        out << type << ' ' << x << ' ' << y << '\n';
    return out;
}

const int C = 1e9;
const int maxN = 500'000;

int main(int argc, char** argv) {
    registerGen(argc, argv, 1);
    bool only_add = opt<bool>("ONLYADD");
    vector<Testcase> tests;
    int n = maxN;
    int m = maxN;
    int q = maxN;
    oset<pii> A, B;
    const int C1 = 1e7;
    while (A.size() < n) {
        int x = rnd.next(-C1, C1);
        int y = rnd.next(-C1, C1);
        A.insert({x, y});
    }
    while (B.size() < m) {
        int x = rnd.next(-C1, C1);
        int y = rnd.next(-C1, C1);
        B.insert({x, y});
    }
    auto change = [](oset<pii> &st, int x, int y) {
        if (st.find({x, y}) != st.end())
            st.erase({x, y});
        else
            st.insert({x, y});
    };
    vector<pii> a(all(A)), b(all(B));
    shuffle(all(a));
    shuffle(all(b));
    vector<query> queries(q);
    bool was_bankrupt = false;
    int L = C1 + 1, R = C1 + 100;
    oset<pii> tmp_a, tmp_b;
    for (int qi = 0; qi < q; qi += 20) {
        tmp_a.clear(), tmp_b.clear();
        for (int qj = qi; qj < qi + 20 && qj < q; qj++) {
            if (only_add || rnd.next(3) || (tmp_a.empty() && tmp_b.empty())) {
                int t = rnd.next(1, 2);
                int x, y;
                if (rnd.next(2))
                    x = rnd.next(-R, -L);
                else
                    x = rnd.next(L, R);
                if (rnd.next(2))
                    y = rnd.next(-R, -L);
                else
                    y = rnd.next(L, R);
                if (t == 1)
                    change(tmp_a, x, y);
                else
                    change(tmp_b, x, y);
                queries[qj] = {t, x, y};
            } else {
                bool del_a = false, del_b = false;
                if (tmp_a.empty())
                    del_b = true;
                else if (tmp_b.empty())
                    del_a = true;
                else {
                    if (rnd.next(2))
                        del_b = true;
                    else
                        del_a = true;
                }
                if (del_a) {
                    int pos = rnd.next(tmp_a.size());
                    auto it = tmp_a.find_by_order(pos);
                    int x = it->first, y = it->second;
                    queries[qj] = {1, x, y};
                    change(tmp_a, x, y);
                } else {
                    int pos = rnd.next(tmp_b.size());
                    auto it = tmp_b.find_by_order(pos);
                    int x = it->first, y = it->second;
                    queries[qj] = {2, x, y};
                    change(tmp_b, x, y);
                }
            }
        }
        L += 100;
        R += 100;
    }
    Testcase test_i(n, m, a, b, q, queries);
    tests.push_back(test_i);
    cout << tests.size() << '\n';
    for (auto &t : tests)
        cout << t;
}