#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;

struct MaxOrders {
    vector<bool> used;
    vector<int> ord00, ord01, ord10, ord11;
    int n;
    
    MaxOrders() {}
    
    MaxOrders(const vector<pii> &a) {
        n = a.size();
        used.resize(n);
        ord00.resize(n);
        iota(all(ord00), 0);
        ord01.resize(n);
        iota(all(ord01), 0);
        ord10.resize(n);
        iota(all(ord10), 0);
        ord11.resize(n);
        iota(all(ord11), 0);
        sort(all(ord00), [&](int i, int j){
            return a[i].first + a[i].second > a[j].first + a[j].second;
        });
        sort(all(ord01), [&](int i, int j){
            return a[i].first - a[i].second > a[j].first - a[j].second;
        });
        sort(all(ord10), [&](int i, int j){
            return -a[i].first + a[i].second > -a[j].first + a[j].second;
        });
        sort(all(ord11), [&](int i, int j){
            return -a[i].first - a[i].second > -a[j].first - a[j].second;
        });
    }
    
    int ptr00 = 0, ptr01 = 0, ptr10 = 0, ptr11 = 0;
    
    int find00() {
        while (ptr00 < n && used[ord00[ptr00]])
            ptr00++;
        int i = ord00[ptr00];
        used[i] = true;
        return i;
    }
    
    int find01() {
        while (ptr01 < n && used[ord01[ptr01]])
            ptr01++;
        int i = ord01[ptr01];
        used[i] = true;
        return i;
    }
    
    int find10() {
        while (ptr10 < n && used[ord10[ptr10]])
            ptr10++;
        int i = ord10[ptr10];
        used[i] = true;
        return i;
    }
    
    int find11() {
        while (ptr11 < n && used[ord11[ptr11]])
            ptr11++;
        int i = ord11[ptr11];
        used[i] = true;
        return i;
    }
};

int main(int argc, char** argv) {
    registerGen(argc, argv, 1);
    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);
    MaxOrders maxsa = a, maxsb = b;
    for (int qi = 0; qi < q; qi++) {
        int t = rnd.next(1, 2);
        MaxOrders &m = t == 1 ? maxsa : maxsb;
        vector<pii> &vec = t == 1 ? a : b;
        int r = rnd.next(4);
        int i;
        if (r == 0)
            i = m.find00();
        else if (r == 1)
            i = m.find01();
        else if (r == 2)
            i = m.find10();
        else
            i = m.find11();
        int x = vec[i].first, y = vec[i].second;
        queries[qi] = {t, x, y};
    }
    Testcase test_i(n, m, a, b, q, queries);
    tests.push_back(test_i);
    cout << tests.size() << '\n';
    for (auto &t : tests)
        cout << t;
}