#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);
    int sumn = 0, summ = 0, sumq = 0;
    bool only_add = opt<bool>("ONLYADD");
    vector<Testcase> tests;
    int n = maxN;
    int m = maxN;
    int q = maxN;
    oset<pii> A, B;
    while (A.size() < n) {
        int x = rnd.next(-C, C);
        int y = rnd.next(-C, C);
        A.insert({x, y});
    }
    while (B.size() < m) {
        int x = rnd.next(-C, C);
        int y = rnd.next(-C, C);
        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;
    for (int qi = 0; qi < q; qi++) {
        if (was_bankrupt) {
            int t = rnd.next(1, 2);
            int x = rnd.next(-C, C);
            int y = rnd.next(-C, C);
            queries[qi] = {t, x, y};
            continue;
        }
        if (only_add || rnd.next(3)) {
            int t = rnd.next(1, 2);
            int x = rnd.next(-C, C);
            int y = rnd.next(-C, C);
            queries[qi] = {t, x, y};
            if (t == 1)
                change(A, x, y);
            else
                change(B, x, y);
        } else {
            int t = rnd.next(1, 2);
            if (t == 1) {
                int pos = rnd.next((int)A.size());
                auto it = A.find_by_order(pos);
                int x = it->first, y = it->second;
                queries[qi] = {t, x, y};
                change(A, x, y);
            } else {
                int pos = rnd.next((int)B.size());
                auto it = B.find_by_order(pos);
                int x = it->first, y = it->second;
                queries[qi] = {t, x, y};
                change(A, x, y);
            }
        }
        if (A.empty() || B.empty())
            was_bankrupt = true;
    }
    Testcase test_i(n, m, a, b, q, queries);
    tests.push_back(test_i);
    cout << tests.size() << '\n';
    for (auto &t : tests)
        cout << t;
}