Problem: cf1254_c
Difficulty: hard
Categories: data structures, math
Time limit: 1000 ms, memory limit: 256 MB

This is an interactive problem.

Khanh has $n$ points on the Cartesian plane, denoted by $a_1, a_2, \ldots, a_n$. All points' coordinates are integers between $-10^9$ and $10^9$, inclusive. No three points are collinear. He says that these points are vertices of a convex polygon; in other words, there exists a permutation $p_1, p_2, \ldots, p_n$ of integers from $1$ to $n$ such that the polygon $a_{p_1} a_{p_2} \ldots a_{p_n}$ is convex and vertices are listed in counter-clockwise order.

Khanh gives you the number $n$, but hides the coordinates of his points. Your task is to guess the above permutation by asking multiple queries. In each query, you give Khanh $4$ integers $t$, $i$, $j$, $k$; where either $t = 1$ or $t = 2$; and $i$, $j$, $k$ are three distinct indices from $1$ to $n$, inclusive. In response, Khanh tells you:

* if $t = 1$, the area of the triangle $a_ia_ja_k$ multiplied by $2$.
* if $t = 2$, the sign of the cross product of two vectors $\overrightarrow{a_ia_j}$ and $\overrightarrow{a_ia_k}$.

Recall that the cross product of vector $\overrightarrow{a} = (x_a, y_a)$ and vector $\overrightarrow{b} = (x_b, y_b)$ is the integer $x_a \cdot y_b - x_b \cdot y_a$. The sign of a number is $1$ it it is positive, and $-1$ otherwise. It can be proven that the cross product obtained in the above queries can not be $0$.

You can ask at most $3 \cdot n$ queries.

Please note that Khanh fixes the coordinates of his points and does not change it while answering your queries. You do not need to guess the coordinates. In your permutation $a_{p_1}a_{p_2}\ldots a_{p_n}$, $p_1$ should be equal to $1$ and the indices of vertices should be listed in counter-clockwise order.

Interaction

You start the interaction by reading $n$ ($3 \leq n \leq 1\,000$) — the number of vertices.

To ask a query, write $4$ integers $t$, $i$, $j$, $k$ ($1 \leq t \leq 2$, $1 \leq i, j, k \leq n$) in a separate line. $i$, $j$ and $k$ should be distinct.

Then read a single integer to get the answer to this query, as explained above. It can be proven that the answer of a query is always an integer.

When you find the permutation, write a number $0$. Then write $n$ integers $p_1, p_2, \ldots, p_n$ in the same line.

After printing a query do not forget to output end of line and flush the output. Otherwise, you will get Idleness limit exceeded. To do this, use:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* see documentation for other languages.

Example

Input

```
6

15

-1

1
```

Output

```
1 1 4 6

2 1 5 6

2 2 1 4

0 1 3 4 2 6 5
```

Note

The image below shows the hidden polygon in the example:

 ![](https://espresso.codeforces.com/3dfb379fcb3da2fb7f4c5654afd8b5b84437b215.png) 

The interaction in the example goes as below:

* Contestant reads $n = 6$.
* Contestant asks a query with $t = 1$, $i = 1$, $j = 4$, $k = 6$.
* Jury answers $15$. The area of the triangle $A_1A_4A_6$ is $7.5$. Note that the answer is two times the area of the triangle.
* Contestant asks a query with $t = 2$, $i = 1$, $j = 5$, $k = 6$.
* Jury answers $-1$. The cross product of $\overrightarrow{A_1A_5} = (2, 2)$ and $\overrightarrow{A_1A_6} = (4, 1)$ is $-2$. The sign of $-2$ is $-1$.
* Contestant asks a query with $t = 2$, $i = 2$, $j = 1$, $k = 4$.
* Jury answers $1$. The cross product of $\overrightarrow{A_2A_1} = (-5, 2)$ and $\overrightarrow{A_2A_4} = (-2, -1)$ is $1$. The sign of $1$ is $1$.
* Contestant says that the permutation is $(1, 3, 4, 2, 6, 5)$.

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

struct Point {
    long long x, y;
    int idx;
};

static long long queries = 0;
static long long query_limit = 0;

static void log_metrics() {
    try {
        tout << "queries=" << queries << "\n";
        tout << "query_limit=" << query_limit << "\n";
        tout.flush();
    } catch (...) {
        
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

static __int128 cross3(const Point& o, const Point& a, const Point& b) {
    __int128 ax = (__int128)a.x - o.x;
    __int128 ay = (__int128)a.y - o.y;
    __int128 bx = (__int128)b.x - o.x;
    __int128 by = (__int128)b.y - o.y;
    return ax * by - ay * bx;
}

static vector<Point> convexHullAllCCW(vector<Point> pts) {
    sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) {
        if (a.x != b.x) return a.x < b.x;
        if (a.y != b.y) return a.y < b.y;
        return a.idx < b.idx;
    });

    int n = (int)pts.size();
    vector<Point> hull;
    hull.reserve(n * 2);

    for (int i = 0; i < n; i++) {
        while ((int)hull.size() >= 2) {
            int m = (int)hull.size();
            __int128 cr = cross3(hull[m - 2], hull[m - 1], pts[i]);
            if (cr > 0) break;
            hull.pop_back();
        }
        hull.push_back(pts[i]);
    }

    int lowerSize = (int)hull.size();
    for (int i = n - 2; i >= 0; i--) {
        while ((int)hull.size() > lowerSize) {
            int m = (int)hull.size();
            __int128 cr = cross3(hull[m - 2], hull[m - 1], pts[i]);
            if (cr > 0) break;
            hull.pop_back();
        }
        hull.push_back(pts[i]);
    }

    if (!hull.empty()) hull.pop_back();

    auto signedArea2 = [&](const vector<Point>& p) -> __int128 {
        __int128 s = 0;
        int m = (int)p.size();
        for (int i = 0; i < m; i++) {
            int j = (i + 1) % m;
            s += (__int128)p[i].x * p[j].y - (__int128)p[i].y * p[j].x;
        }
        return s;
    };

    if ((int)hull.size() >= 3) {
        __int128 a2 = signedArea2(hull);
        if (a2 < 0) reverse(hull.begin(), hull.end());
    }
    return hull;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);

    try {
        int n = inf.readInt(3, 1000, "n");

        vector<Point> pts(n + 1);
        vector<Point> list;
        list.reserve(n);

        for (int i = 1; i <= n; i++) {
            long long x = inf.readLong(-1000000000LL, 1000000000LL, "x");
            long long y = inf.readLong(-1000000000LL, 1000000000LL, "y");
            pts[i] = Point{x, y, i};
            list.push_back(pts[i]);
        }

        query_limit = 3LL * n;
        long long hard_cap = max(200000LL, 10LL * query_limit);

        log_metrics(); 

        cout << n << "\n" << flush;

        vector<Point> hull = convexHullAllCCW(list);
        if ((int)hull.size() != n) {
            finish(_pe, "interactor error: points are not all on convex hull");
        }

        int pos1 = -1;
        for (int i = 0; i < n; i++) {
            if (hull[i].idx == 1) {
                pos1 = i;
                break;
            }
        }
        if (pos1 == -1) {
            finish(_pe, "interactor error: index 1 not found");
        }

        vector<int> expected;
        expected.reserve(n);
        for (int t = 0; t < n; t++) expected.push_back(hull[(pos1 + t) % n].idx);

        while (true) {
            long long t;
            if (!(cin >> t)) {
                finish(_pe, "unexpected EOF from contestant");
            }

            if (t == 0) {
                vector<int> ans(n);
                for (int i = 0; i < n; i++) {
                    long long v;
                    if (!(cin >> v)) finish(_pe, "missing permutation element(s)");
                    if (v < INT_MIN || v > INT_MAX) finish(_pe, "permutation element out of range");
                    ans[i] = (int)v;
                }

                if (ans[0] != 1) finish(_wa, "p1 must be 1");

                vector<int> seen(n + 1, 0);
                for (int i = 0; i < n; i++) {
                    if (ans[i] < 1 || ans[i] > n) finish(_wa, "permutation index out of [1..n]");
                    if (seen[ans[i]]++) finish(_wa, "permutation contains duplicates");
                }

                if (ans != expected) finish(_wa, "wrong permutation");
                finish(_ok, "OK");
            }

            if (t != 1 && t != 2) {
                finish(_pe, "invalid query type");
            }

            long long ii, jj, kk;
            if (!(cin >> ii >> jj >> kk)) {
                finish(_pe, "malformed query");
            }
            if (ii < 1 || ii > n || jj < 1 || jj > n || kk < 1 || kk > n) {
                finish(_pe, "query index out of range");
            }
            if (ii == jj || ii == kk || jj == kk) {
                finish(_pe, "query indices must be distinct");
            }

            queries++;
            if (queries > hard_cap) {
                finish(_pe, "hard cap exceeded (likely infinite loop)");
            }

            const Point& A = pts[(int)ii];
            const Point& B = pts[(int)jj];
            const Point& C = pts[(int)kk];
            __int128 cr = cross3(A, B, C);

            if (t == 1) {
                __int128 v = cr;
                if (v < 0) v = -v;
                long long out = (long long)v;
                cout << out << "\n" << flush;
            } else {
                int sgn = (cr > 0) ? 1 : -1;
                cout << sgn << "\n" << flush;
            }
        }
    } catch (const exception& e) {
        finish(_pe, string("interactor exception: ") + e.what());
    } catch (...) {
        finish(_pe, "interactor exception");
    }
}


Adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

struct Pt {
    long long x, y;
    int id;
};

static long long queries = 0;
static long long query_limit = 0;

static void log_metrics() {
    try {
        tout << "queries=" << queries << '\n';
        tout << "query_limit=" << query_limit << '\n';
        tout.flush();
    } catch (...) {
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

static __int128 cross128(long long ax, long long ay, long long bx, long long by) {
    return (__int128)ax * (__int128)by - (__int128)ay * (__int128)bx;
}

static __int128 cross128(const Pt& o, const Pt& a, const Pt& b) {
    return cross128(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y);
}

static long long i128_to_ll_checked(__int128 v) {
    if (v < (__int128)LLONG_MIN || v > (__int128)LLONG_MAX) return 0; 
    return (long long)v;
}

struct SplitMix64 {
    uint64_t x;
    explicit SplitMix64(uint64_t seed) : x(seed) {}
    uint64_t nextU64() {
        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);
        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
        return z ^ (z >> 31);
    }
    long long nextLL(long long lo, long long hi) {
        if (lo > hi) std::swap(lo, hi);
        uint64_t span = (uint64_t)(hi - lo + 1);
        uint64_t r = nextU64();
        return lo + (long long)(r % span);
    }
    int nextInt(int lo, int hi) { return (int)nextLL(lo, hi); }
};

static long long llabsll(long long v) { return v < 0 ? -v : v; }

static long long gcdll(long long a, long long b) {
    a = llabsll(a);
    b = llabsll(b);
    while (b) {
        long long t = a % b;
        a = b;
        b = t;
    }
    return a;
}

static vector<long long> pickUniqueDet(int n, long long lo, long long hi, SplitMix64& rng) {
    set<long long> s;
    while ((int)s.size() < n) {
        s.insert(rng.nextLL(lo, hi));
    }
    return vector<long long>(s.begin(), s.end());
}

template <class T>
static void shuffleDet(vector<T>& v, SplitMix64& rng) {
    for (int i = (int)v.size() - 1; i > 0; --i) {
        int j = rng.nextInt(0, i);
        swap(v[i], v[j]);
    }
}

struct Vec {
    long long x, y;
};

static __int128 crossVec(const Vec& a, const Vec& b) {
    return (__int128)a.x * (__int128)b.y - (__int128)a.y * (__int128)b.x;
}

static int halfPlane(const Vec& v) {
    if (v.y > 0) return 1;
    if (v.y < 0) return 0;
    return v.x > 0 ? 1 : 0;
}

static bool isStrictlyConvexCCW(const vector<pair<long long, long long>>& poly) {
    int n = (int)poly.size();
    if (n < 3) return false;
    __int128 sign = 0;
    for (int i = 0; i < n; i++) {
        auto o = poly[i];
        auto a = poly[(i + 1) % n];
        auto b = poly[(i + 2) % n];
        __int128 cr = cross128(a.first - o.first, a.second - o.second, b.first - o.first, b.second - o.second);
        if (cr == 0) return false;
        if (sign == 0) sign = (cr > 0 ? 1 : -1);
        else if ((cr > 0 ? 1 : -1) != sign) return false;
    }
    return sign > 0;
}

static vector<pair<long long, long long>> genConvexValtrDet(int n, long long W, long long H, uint64_t seed) {
    SplitMix64 rng(seed);

    vector<long long> xs = pickUniqueDet(n, 0, W, rng);
    vector<long long> ys = pickUniqueDet(n, 0, H, rng);
    sort(xs.begin(), xs.end());
    sort(ys.begin(), ys.end());

    auto splitDiffs = [&](const vector<long long>& v) -> vector<long long> {
        vector<long long> upper, lower;
        long long lastU = v[0], lastL = v[0];
        for (int i = 1; i <= n - 2; i++) {
            if (rng.nextInt(0, 1) == 0) {
                upper.push_back(v[i] - lastU);
                lastU = v[i];
            } else {
                lower.push_back(v[i] - lastL);
                lastL = v[i];
            }
        }
        upper.push_back(v[n - 1] - lastU);
        lower.push_back(v[n - 1] - lastL);

        vector<long long> res;
        res.reserve(n);
        for (long long d : upper) res.push_back(d);
        for (long long d : lower) res.push_back(-d);
        return res;
    };

    vector<long long> dx = splitDiffs(xs);
    vector<long long> dy = splitDiffs(ys);
    shuffleDet(dy, rng);

    vector<Vec> edges(n);
    for (int i = 0; i < n; i++) edges[i] = Vec{dx[i], dy[i]};

    sort(edges.begin(), edges.end(), [&](const Vec& a, const Vec& b) {
        int ha = halfPlane(a), hb = halfPlane(b);
        if (ha != hb) return ha > hb;
        __int128 cr = crossVec(a, b);
        if (cr != 0) return cr > 0;
        long long la = llabsll(a.x) + llabsll(a.y);
        long long lb = llabsll(b.x) + llabsll(b.y);
        return la < lb;
    });

    vector<pair<long long, long long>> poly;
    poly.reserve(n);
    long long cx = 0, cy = 0;
    for (int i = 0; i < n; i++) {
        cx += edges[i].x;
        cy += edges[i].y;
        poly.push_back({cx, cy});
    }

    long long minx = poly[0].first, miny = poly[0].second;
    for (auto& p : poly) {
        minx = min(minx, p.first);
        miny = min(miny, p.second);
    }
    for (auto& p : poly) {
        p.first -= minx;
        p.second -= miny;
    }
    return poly;
}

static vector<Pt> convexHullStrict(vector<Pt> pts) {
    sort(pts.begin(), pts.end(), [&](const Pt& a, const Pt& b) {
        if (a.x != b.x) return a.x < b.x;
        if (a.y != b.y) return a.y < b.y;
        return a.id < b.id;
    });
    int n = (int)pts.size();
    if (n <= 1) return pts;

    vector<Pt> lower, upper;
    for (const auto& p : pts) {
        while ((int)lower.size() >= 2 && cross128(lower[(int)lower.size() - 2], lower.back(), p) <= 0) lower.pop_back();
        lower.push_back(p);
    }
    for (int i = n - 1; i >= 0; --i) {
        const auto& p = pts[i];
        while ((int)upper.size() >= 2 && cross128(upper[(int)upper.size() - 2], upper.back(), p) <= 0) upper.pop_back();
        upper.push_back(p);
    }

    lower.pop_back();
    upper.pop_back();
    lower.insert(lower.end(), upper.begin(), upper.end());
    return lower; 
}

static bool hasAnyThreeCollinear(const vector<Pt>& pts) {
    int n = (int)pts.size();
    vector<pair<long long, long long>> dirs;
    dirs.reserve(n - 1);
    for (int i = 0; i < n; i++) {
        dirs.clear();
        for (int j = 0; j < n; j++) if (j != i) {
            long long dx = pts[j].x - pts[i].x;
            long long dy = pts[j].y - pts[i].y;
            long long g = gcdll(dx, dy);
            dx /= g;
            dy /= g;
            if (dx < 0 || (dx == 0 && dy < 0)) {
                dx = -dx;
                dy = -dy;
            }
            dirs.push_back({dx, dy});
        }
        sort(dirs.begin(), dirs.end());
        for (int k = 1; k < (int)dirs.size(); k++) {
            if (dirs[k] == dirs[k - 1]) return true;
        }
    }
    return false;
}

static vector<Pt> buildDeterministicInstanceFromN(int n) {
    const long long LIM = 1000000000LL;
    const long long W = 700000000LL;
    const long long H = 700000000LL;

    uint64_t baseSeed = 0x1234567890abcdefULL ^ (uint64_t)n * 0x9e3779b97f4a7c15ULL;

    vector<pair<long long, long long>> poly;
    for (int attempt = 0; attempt < 64; attempt++) {
        uint64_t seed = baseSeed + (uint64_t)attempt * 0xD1B54A32D192ED03ULL;
        poly = genConvexValtrDet(n, W, H, seed);

        if (!isStrictlyConvexCCW(poly)) {
            reverse(poly.begin(), poly.end());
        }
        if (!isStrictlyConvexCCW(poly)) continue;

        long long minx = poly[0].first, miny = poly[0].second;
        long long maxx = poly[0].first, maxy = poly[0].second;
        for (auto& p : poly) {
            minx = min(minx, p.first);
            miny = min(miny, p.second);
            maxx = max(maxx, p.first);
            maxy = max(maxy, p.second);
        }
        long long sx = -((minx + maxx) / 2);
        long long sy = -((miny + maxy) / 2);
        for (auto& p : poly) {
            p.first += sx;
            p.second += sy;
            if (p.first < -LIM || p.first > LIM || p.second < -LIM || p.second > LIM) {
                sx = sy = 0;
                break;
            }
        }
        bool inRange = true;
        for (auto& p : poly) {
            if (p.first < -LIM || p.first > LIM || p.second < -LIM || p.second > LIM) {
                inRange = false;
                break;
            }
        }
        if (!inRange) continue;

        vector<Pt> tmp;
        tmp.reserve(n);
        for (int i = 0; i < n; i++) tmp.push_back(Pt{poly[i].first, poly[i].second, i + 1});
        if (hasAnyThreeCollinear(tmp)) continue;

        vector<Pt> hull = convexHullStrict(tmp);
        if ((int)hull.size() != n) continue;

        SplitMix64 rng(seed ^ 0xA5A5A5A5A5A5A5A5ULL);
        int pos1 = (n <= 6 ? 0 : rng.nextInt(0, n - 1));

        vector<Pt> coords(n + 1);
        coords[1] = Pt{poly[pos1].first, poly[pos1].second, 1};

        vector<int> pos;
        pos.reserve(n - 1);
        for (int i = 0; i < n; i++) if (i != pos1) pos.push_back(i);
        shuffleDet(pos, rng);

        for (int idx = 2; idx <= n; idx++) {
            int p = pos[idx - 2];
            coords[idx] = Pt{poly[p].first, poly[p].second, idx};
        }

        vector<Pt> all;
        all.reserve(n);
        for (int i = 1; i <= n; i++) all.push_back(coords[i]);
        vector<Pt> hull2 = convexHullStrict(all);
        if ((int)hull2.size() != n) continue;
        if (hasAnyThreeCollinear(all)) continue;

        return coords;
    }

    
    
    int m = n / 2;
    long long D = 500000000LL;
    vector<pair<long long, long long>> fallback;
    fallback.reserve(n);
    for (int i = 0; i <= m; i++) fallback.push_back({i, 1LL * i * i});
    if (n % 2 == 0) {
        for (int i = m - 1; i >= 1; --i) fallback.push_back({i, -1LL * i * i - D});
    } else {
        for (int i = m; i >= 1; --i) fallback.push_back({i, -1LL * i * i - D});
    }
    if (!isStrictlyConvexCCW(fallback)) reverse(fallback.begin(), fallback.end());

    vector<Pt> coords(n + 1);
    for (int i = 1; i <= n; i++) {
        coords[i] = Pt{fallback[i - 1].first, fallback[i - 1].second, i};
    }
    return coords;
}

static bool readLongLongSafe(long long& out) {
    if (!(cin >> out)) return false;
    return true;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);

    int n = inf.readInt();
    if (n < 3 || n > 1000) finish(_pe, "invalid n in input");

    vector<Pt> coords(n + 1);
    bool hasCoords = false;

    if (!inf.seekEof()) {
        hasCoords = true;
        for (int i = 1; i <= n; i++) {
            long long x = inf.readLong();
            long long y = inf.readLong();
            coords[i] = Pt{x, y, i};
        }
    } else {
        coords = buildDeterministicInstanceFromN(n);
    }

    query_limit = 3LL * n;
    log_metrics(); 

    cout << n << endl;

    const long long hard_cap = max(200000LL, 10LL * query_limit);

    auto triangleCross = [&](int i, int j, int k) -> __int128 {
        long long x1 = coords[j].x - coords[i].x;
        long long y1 = coords[j].y - coords[i].y;
        long long x2 = coords[k].x - coords[i].x;
        long long y2 = coords[k].y - coords[i].y;
        return cross128(x1, y1, x2, y2);
    };

    auto getCorrectOrder = [&]() -> vector<int> {
        vector<Pt> pts;
        pts.reserve(n);
        for (int i = 1; i <= n; i++) pts.push_back(coords[i]);
        vector<Pt> hull = convexHullStrict(pts);
        if ((int)hull.size() != n) finish(_pe, "internal: points are not all hull vertices");
        int pos1 = -1;
        for (int i = 0; i < n; i++) if (hull[i].id == 1) { pos1 = i; break; }
        if (pos1 == -1) finish(_pe, "internal: point 1 not found on hull");
        vector<int> order;
        order.reserve(n);
        for (int i = 0; i < n; i++) order.push_back(hull[(pos1 + i) % n].id);
        return order;
    };

    while (true) {
        long long tll;
        if (!readLongLongSafe(tll)) finish(_pe, "unexpected EOF from contestant");
        if (tll == 0) {
            vector<int> ans(n);
            for (int i = 0; i < n; i++) {
                long long v;
                if (!readLongLongSafe(v)) finish(_pe, "missing permutation after 0");
                if (v < 1 || v > n) finish(_pe, "permutation element out of range");
                ans[i] = (int)v;
            }
            if (ans[0] != 1) finish(_wa, "p1 must be 1");
            vector<int> seen(n + 1, 0);
            for (int v : ans) {
                if (seen[v]) finish(_pe, "permutation contains duplicates");
                seen[v] = 1;
            }
            vector<int> correct = getCorrectOrder();
            if (ans == correct) finish(_ok, "correct");
            finish(_wa, "wrong order");
        }

        int t = (int)tll;
        if (!(t == 1 || t == 2)) finish(_pe, "invalid query type");
        long long ill, jll, kll;
        if (!readLongLongSafe(ill) || !readLongLongSafe(jll) || !readLongLongSafe(kll)) finish(_pe, "incomplete query");
        int i = (int)ill, j = (int)jll, k = (int)kll;
        if (i < 1 || i > n || j < 1 || j > n || k < 1 || k > n) finish(_pe, "index out of range");
        if (i == j || i == k || j == k) finish(_pe, "indices must be distinct");

        queries++;
        if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");

        __int128 cr = triangleCross(i, j, k);
        if (cr == 0) finish(_pe, "internal: collinear triple encountered");

        if (t == 2) {
            long long res = (cr > 0 ? 1 : -1);
            cout << res << endl;
        } else {
            __int128 v = cr;
            if (v < 0) v = -v;
            long long res = i128_to_ll_checked(v);
            if (res <= 0) finish(_pe, "internal: non-positive area");
            cout << res << endl;
        }
    }
}


Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

struct Vec {
    ll x, y;
};

static ll cross(const Vec& a, const Vec& b) {
    return a.x * b.y - a.y * b.x;
}

static ll cross3(const pair<ll, ll>& o, const pair<ll, ll>& a, const pair<ll, ll>& b) {
    return (a.first - o.first) * (b.second - o.second) - (a.second - o.second) * (b.first - o.first);
}

template <class T>
static void shuffleVec(vector<T>& v) {
    for (int i = (int)v.size() - 1; i > 0; --i) {
        int j = rnd.next(0, i);
        swap(v[i], v[j]);
    }
}

static vector<ll> pickUnique(int n, ll lo, ll hi) {
    set<ll> s;
    while ((int)s.size() < n) s.insert(rnd.next(lo, hi));
    return vector<ll>(s.begin(), s.end());
}

static bool isStrictlyConvexCCW(vector<pair<ll, ll>>& poly) {
    int n = (int)poly.size();
    if (n < 3) return false;

    ll sign = 0;
    for (int i = 0; i < n; i++) {
        ll cr = cross3(poly[i], poly[(i + 1) % n], poly[(i + 2) % n]);
        if (cr == 0) return false;
        if (sign == 0) sign = (cr > 0 ? 1 : -1);
        else if ((cr > 0 ? 1 : -1) != sign) return false;
    }
    if (sign < 0) reverse(poly.begin(), poly.end());
    return true;
}

static vector<pair<ll, ll>> genConvexValtr(int n, ll W, ll H) {
    vector<ll> xs = pickUnique(n, 0, W);
    vector<ll> ys = pickUnique(n, 0, H);
    sort(xs.begin(), xs.end());
    sort(ys.begin(), ys.end());

    auto splitDiffs = [&](const vector<ll>& v) -> vector<ll> {
        vector<ll> upper, lower;
        ll lastU = v[0], lastL = v[0];
        for (int i = 1; i <= n - 2; i++) {
            if (rnd.next(0, 1) == 0) {
                upper.push_back(v[i] - lastU);
                lastU = v[i];
            } else {
                lower.push_back(v[i] - lastL);
                lastL = v[i];
            }
        }
        upper.push_back(v[n - 1] - lastU);
        lower.push_back(v[n - 1] - lastL);

        vector<ll> res;
        res.reserve(n);
        for (ll d : upper) res.push_back(d);
        for (ll d : lower) res.push_back(-d);
        return res;
    };

    vector<ll> dx = splitDiffs(xs);
    vector<ll> dy = splitDiffs(ys);
    shuffleVec(dy);

    vector<Vec> edges(n);
    for (int i = 0; i < n; i++) edges[i] = Vec{dx[i], dy[i]};

    auto half = [&](const Vec& v) -> int {
        if (v.y > 0) return 1;
        if (v.y < 0) return 0;
        return v.x > 0 ? 1 : 0;
    };

    sort(edges.begin(), edges.end(), [&](const Vec& a, const Vec& b) {
        int ha = half(a), hb = half(b);
        if (ha != hb) return ha > hb;
        ll cr = cross(a, b);
        if (cr != 0) return cr > 0;
        ll la = llabs(a.x) + llabs(a.y);
        ll lb = llabs(b.x) + llabs(b.y);
        return la < lb;
    });

    vector<pair<ll, ll>> poly;
    poly.reserve(n);
    ll cx = 0, cy = 0;
    for (int i = 0; i < n; i++) {
        cx += edges[i].x;
        cy += edges[i].y;
        poly.push_back({cx, cy});
    }

    ll minx = poly[0].first, miny = poly[0].second;
    ll maxx = poly[0].first, maxy = poly[0].second;
    for (auto& p : poly) {
        minx = min(minx, p.first);
        miny = min(miny, p.second);
        maxx = max(maxx, p.first);
        maxy = max(maxy, p.second);
    }
    for (auto& p : poly) {
        p.first -= minx;
        p.second -= miny;
    }
    return poly;
}

static vector<pair<ll, ll>> buildInstanceNon(int seed, int n, ll lim) {
    if (seed == 1) {
        vector<pair<ll, ll>> pts = {
            {lim, 0},
            {0, lim},
            {-lim, -lim}
        };
        return pts;
    }
    if (seed == 2) {
        vector<pair<ll, ll>> pts = {
            {-lim, -1},
            {lim, -1},
            {lim, 1},
            {-lim, 1}
        };
        return pts;
    }

    ll W = lim, H = lim;
    if (seed == 3) {
        W = lim;
        H = 2000000;
        if (H < n + 10) H = (ll)n + 10;
    } else {
        int shape = rnd.next(0, 2);
        if (shape == 0) {
            W = lim;
            H = rnd.next(2000000LL, 30000000LL);
            if (H < n + 10) H = (ll)n + 10;
        } else if (shape == 1) {
            H = lim;
            W = rnd.next(2000000LL, 30000000LL);
            if (W < n + 10) W = (ll)n + 10;
        } else {
            W = lim;
            H = lim;
        }
    }

    for (int attempt = 0; attempt < 200; attempt++) {
        vector<pair<ll, ll>> poly = genConvexValtr(n, W, H);
        if (!isStrictlyConvexCCW(poly)) continue;

        ll maxx = poly[0].first, maxy = poly[0].second;
        ll minx = poly[0].first, miny = poly[0].second;
        for (auto& p : poly) {
            minx = min(minx, p.first);
            miny = min(miny, p.second);
            maxx = max(maxx, p.first);
            maxy = max(maxy, p.second);
        }
        for (auto& p : poly) {
            p.first -= minx;
            p.second -= miny;
        }
        maxx -= minx;
        maxy -= miny;

        if (maxx > 2 * lim || maxy > 2 * lim) continue;

        ll txLo = -lim;
        ll txHi = lim - maxx;
        ll tyLo = -lim;
        ll tyHi = lim - maxy;
        if (txLo > txHi || tyLo > tyHi) continue;

        ll tx = rnd.next(txLo, txHi);
        ll ty = rnd.next(tyLo, tyHi);
        for (auto& p : poly) {
            p.first += tx;
            p.second += ty;
            if (p.first < -lim || p.first > lim || p.second < -lim || p.second > lim) {
                tx = ty = 0;
                break;
            }
        }

        bool ok = true;
        for (auto& p : poly) {
            if (p.first < -lim || p.first > lim || p.second < -lim || p.second > lim) {
                ok = false;
                break;
            }
        }
        if (!ok) continue;

        if (!isStrictlyConvexCCW(poly)) continue;
        return poly;
    }

    
    vector<pair<ll, ll>> pts;
    for (int i = 0; i < n; i++) pts.push_back({-lim + i, -lim + 2LL * i + 1});
    return pts;
}

static vector<pair<ll, ll>> assignIndices(const vector<pair<ll, ll>>& polyCCW, int seed) {
    int n = (int)polyCCW.size();
    vector<pair<ll, ll>> coords(n + 1);

    int pos1;
    if (n <= 6) pos1 = 0;
    else if (seed == 3) pos1 = n / 2;
    else pos1 = rnd.next(0, n - 1);

    coords[1] = polyCCW[pos1];

    vector<int> pos;
    pos.reserve(n - 1);
    for (int i = 0; i < n; i++) if (i != pos1) pos.push_back(i);
    shuffleVec(pos);

    for (int idx = 2; idx <= n; idx++) coords[idx] = polyCCW[pos[idx - 2]];
    return coords;
}

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);

    string mode = opt<string>("mode", "non");
    int nOpt = opt<int>("n", 1000);
    ll lim = opt<ll>("limit", 1000000000LL);

    int seed = 0;
    if (argc >= 2) seed = atoi(argv[1]);

    auto clampN = [&](int n) -> int {
        n = max(3, min(1000, n));
        return n;
    };

    int n;
    if (seed == 1) n = 3;
    else if (seed == 2) n = 4;
    else if (seed == 3) n = 1000;
    else {
        n = clampN(nOpt);
        if (n >= 10) {
            int lo = max(3, n - 50);
            n = rnd.next(lo, n);
        }
    }

    if (mode == "adp") {
        cout << n << "\n";
        return 0;
    }

    if (mode != "non") mode = "non";

    vector<pair<ll, ll>> poly = buildInstanceNon(seed, n, lim);
    if ((int)poly.size() != n) {
        poly.resize(n);
    }

    vector<pair<ll, ll>> tmp = poly;
    isStrictlyConvexCCW(tmp);

    vector<pair<ll, ll>> coords = assignIndices(tmp, seed);

    cout << n << "\n";
    for (int i = 1; i <= n; i++) {
        cout << coords[i].first << " " << coords[i].second << "\n";
    }
    return 0;
}