Submission #1336340

#TimeUsernameProblemLanguageResultExecution timeMemory
1336340MisterReaperIOI Fever (JOI21_fever)C++20
100 / 100
896 ms16876 KiB
#include <bits/stdc++.h>

using i64 = long long;

#ifdef DEBUG
    #include "debug.h"
#else
    #define debug(...) void(23)
#endif

constexpr int MAX = int(1E9) + 5;
constexpr int dx[] = {0, +1, 0, -1};
constexpr int dy[] = {+1, 0, -1, 0};

template<typename T>
using min_pq = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template<typename T>
bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

struct DSU {
    std::vector<int> f;
    DSU(int n) : f(n) {
        std::iota(f.begin(), f.end(), 0);
    }
    int get(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
    bool unite(int a, int b) {
        assert(a == get(a));
        a = get(a), b = get(b);
        if (a == b) {
            return false;
        } 
        f[a] = b;
        return true;
    }
    bool same(int a, int b) {
        return get(a) == get(b);
    }
};

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int N;
    std::cin >> N;

    std::vector<std::array<int, 2>> A(N);
    for (int i = 0; i < N; ++i) {
        std::cin >> A[i][0] >> A[i][1];
        A[i][0] *= 2;
        A[i][1] *= 2;
    }

    auto meet = [&](int i, int j, int dir) -> std::pair<int, int> {
        if (A[i][0] == A[j][0]) {
            if (dir == 0 && A[i][1] <= A[j][1]) {
                return {2, (A[j][1] - A[i][1]) / 2};
            } else if (dir == 2 && A[i][1] >= A[j][1]) {
                return {0, (A[i][1] - A[j][1]) / 2};
            }
            return {-1, -1};
        } 
        if (A[i][1] == A[j][1]) {
            if (dir == 1 && A[i][0] <= A[j][0]) {
                return {3, (A[j][0] - A[i][0]) / 2};
            } else if (dir == 3 && A[i][0] >= A[j][0]) {
                return {1, (A[i][0] - A[j][0]) / 2};
            }
            return {-1, -1};
        } 
        int dis = std::abs(A[i][0] - A[j][0]);
        if (A[i][0] + A[i][1] == A[j][0] + A[j][1]) {
            if (dir % 2 == 0) {
                if (dir == 0 ? A[i][1] <= A[j][1] : A[i][1] >= A[j][1]) {
                    int ndir = (dir == 0 ? 1 : 3);
                    return {ndir, dis};
                }
                return {-1, -1};
            } else {
                if (dir == 1 ? A[i][0] <= A[j][0] : A[i][0] >= A[j][0]) {
                    int ndir = (dir == 1 ? 0 : 2);
                    return {ndir, dis};
                }
                return {-1, -1};
            }
        } 
        if (A[i][0] - A[i][1] == A[j][0] - A[j][1]) {
            if (dir % 2 == 0) {
                if (dir == 0 ? A[i][1] <= A[j][1] : A[i][1] >= A[j][1]) {
                    int ndir = (dir == 0 ? 3 : 1);
                    return {ndir, dis};
                }
                return {-1, -1};
            } else {
                if (dir == 1 ? A[i][0] <= A[j][0] : A[i][0] >= A[j][0]) {
                    int ndir = (dir == 1 ? 2 : 0);
                    return {ndir, dis};
                }
                return {-1, -1};
            }
        }
        return {-1, -1};
    };

    int ans = 0;
    auto work = [&]() -> void {
        std::vector<std::vector<std::pair<int, int>>> gr(4, std::vector<std::pair<int, int>>(N));
        for (int i = 0; i < N; ++i) {
            gr[0][i] = std::pair{A[i][0], i};
            gr[1][i] = std::pair{A[i][1], i};
            gr[2][i] = std::pair{A[i][0] - A[i][1], i};
            gr[3][i] = std::pair{A[i][0] + A[i][1], i};
        }
        std::vector<std::vector<int>> igr(4, std::vector<int>(N));
        std::sort(gr[0].begin(), gr[0].end(), [&](auto lhs, auto rhs) {
            if (lhs.first != rhs.first) {
                return lhs.first < rhs.first;
            }
            return A[lhs.second][1] < A[rhs.second][1];
        });
        std::sort(gr[1].begin(), gr[1].end(), [&](auto lhs, auto rhs) {
            if (lhs.first != rhs.first) {
                return lhs.first < rhs.first;
            }
            return A[lhs.second][0] < A[rhs.second][0];
        });
        std::sort(gr[2].begin(), gr[2].end(), [&](auto lhs, auto rhs) {
            if (lhs.first != rhs.first) {
                return lhs.first < rhs.first;
            }
            return A[lhs.second][1] < A[rhs.second][1];
        });
        std::sort(gr[3].begin(), gr[3].end(), [&](auto lhs, auto rhs) {
            if (lhs.first != rhs.first) {
                return lhs.first < rhs.first;
            }
            return A[lhs.second][1] < A[rhs.second][1];
        });
        for (int i = 0; i < 4; ++i) {
            for (int j = 0; j < N; ++j) {
                igr[i][gr[i][j].second] = j;
            }
        }
        std::vector<DSU> dsus(8, N);
        std::vector<std::vector<int>> dir(8, std::vector<int>(N, -1));
        std::vector<int> vis(N);
        std::vector<std::vector<int>> dis(8, std::vector<int>(N, MAX));
        std::vector<min_pq<std::pair<int, int>>> pqs(8);
        auto getid = [&](int x, int p) -> int {
            if (x / 2 == 0) {
                p = gr[0][p].second;
                return p;
            } else if (x / 2 == 1) {
                p = gr[1][p].second;
                return p;
            } else if (x / 2 == 2) {
                p = gr[2][p].second;
                return p;
            } else if (x / 2 == 3) {
                p = gr[3][p].second;
                return p;
            } else {
                assert(false);
                return -1;
            }
        };
        auto same = [&](int x, int a, int b) -> bool {
            if (x / 2 == 0) {
                return A[a][0] == A[b][0];
            } else if (x / 2 == 1) {
                return A[a][1] == A[b][1];
            } else if (x / 2 == 2) {
                return A[a][0] - A[a][1] == A[b][0] - A[b][1];
            } else if (x / 2 == 3) {
                return A[a][0] + A[a][1] == A[b][0] + A[b][1];
            } else {
                assert(false);
                return false;
            }
        };
        auto add = [&](int x, int v, int ds, int dr) -> void {
            debug(x, v, ds, dr);
            if (dis[x][v] > ds) {
                dis[x][v] = ds;
                dir[x][v] = dr;
                pqs[x].emplace(dis[x][v], v);
            }
        };
        auto add_next = [&](int x, int v) -> void {
            if (v == 0) {
                return;
            }
            debug(x, v);
            if (x == 0) {
                if (igr[0][v] == N - 1) {
                    return;
                }
                int z = dsus[0].get(igr[0][v] + 1);
                z = getid(0, z);
                if (!same(0, v, z)) {
                    return;
                }
                int nc = dis[0][v] + (A[z][1] - A[v][1]) / 2;
                assert((A[z][0] - A[v][0]) / 2 >= 0);
                add(0, z, nc, dir[0][v]);
            } else if (x == 1) {
                if (igr[0][v] == 0) {
                    return;
                }
                int z = dsus[1].get(igr[0][v] - 1);
                z = getid(1, z);
                if (!same(1, v, z)) {
                    return;
                }
                int nc = dis[1][v] + (A[v][1] - A[z][1]) / 2;
                assert((A[v][1] - A[z][1]) / 2 >= 0);
                add(1, z, nc, dir[1][v]);
            } else if (x == 2) {
                if (igr[1][v] == N - 1) {
                    return;
                }
                int z = dsus[2].get(igr[1][v] + 1);
                z = getid(2, z);
                if (!same(2, v, z)) {
                    return;
                }
                int nc = dis[2][v] + (A[z][0] - A[v][0]) / 2;
                assert((A[z][0] - A[v][0]) / 2 >= 0);
                add(2, z, nc, dir[2][v]);
            } else if (x == 3) {
                if (igr[1][v] == 0) {
                    return;
                }
                int z = dsus[3].get(igr[1][v] - 1);
                z = getid(3, z);
                if (!same(3, v, z)) {
                    return;
                }
                int nc = dis[3][v] + (A[v][0] - A[z][0]) / 2;
                assert((A[v][0] - A[z][0]) / 2 >= 0);
                add(3, z, nc, dir[3][v]);
            } else if (x == 4) {
                if (igr[2][v] == N - 1) {
                    return;
                }
                int z = dsus[4].get(igr[2][v] + 1);
                z = getid(4, z);
                if (!same(4, v, z)) {
                    return;
                }
                int nc = dis[4][v] + (A[z][0] - A[v][0]);
                assert((A[z][0] - A[v][0]) >= 0);
                add(4, z, nc, dir[4][v]);
            } else if (x == 5) {
                if (igr[2][v] == 0) {
                    return;
                }
                int z = dsus[5].get(igr[2][v] - 1);
                z = getid(5, z);
                if (!same(5, v, z)) {
                    return;
                }
                int nc = dis[5][v] + (A[v][1] - A[z][1]);
                assert((A[v][1] - A[z][1]) >= 0);
                add(5, z, nc, dir[5][v]);
            } else if (x == 6) {
                if (igr[3][v] == N - 1) {
                    return;
                }
                int z = dsus[6].get(igr[3][v] + 1);
                z = getid(6, z);
                if (!same(6, v, z)) {
                    return;
                }
                int nc = dis[6][v] + (A[z][1] - A[v][1]);
                assert((A[z][1] - A[v][1]) >= 0);
                add(6, z, nc, dir[6][v]);
            } else if (x == 7) {
                if (igr[3][v] == 0) {
                    return;
                }
                int z = dsus[7].get(igr[3][v] - 1);
                z = getid(7, z);
                if (!same(7, v, z)) {
                    return;
                }
                int nc = dis[7][v] + (A[v][1] - A[z][1]);
                assert((A[v][1] - A[z][1]) >= 0);
                add(7, z, nc, dir[7][v]);
            } else {
                assert(false);
            }
        };
        auto jump_nexts = [&](int v, int ds, int dr) -> void {
            debug("jump nexts", v, ds, dr);
            for (int i = 0; i < 8; ++i) {
                if (i % 2 == 0) {
                    int p = igr[i / 2][v];
                    if (p != N - 1) {
                        dsus[i].unite(p, p + 1);
                    }
                } else {
                    int p = igr[i / 2][v];
                    if (p != 0) {
                        dsus[i].unite(p, p - 1);
                    }
                }
            }
            if (dr == 0) {
                // 0, v, ds, 2
                {
                    int p = dsus[0].get(igr[0][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? (1 << i) : 1;
                        auto[met1, met2] = meet(v, getid(0, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k < N) {
                                int nxt = dsus[0].get(p + k);
                                auto[net1, net2] = meet(v, getid(0, nxt), dr);
                                if (same(0, v, getid(0, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(0, v, getid(0, p))) {
                        auto[met1, met2] = meet(v, getid(0, p), dr);
                        if (met2 >= ds) {
                            add(0, getid(0, p), met2, 2);
                        }
                    }
                }
                // 4, v, ds, 3
                {
                    int p = dsus[4].get(igr[2][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? (1 << i) : 1;
                        auto[met1, met2] = meet(v, getid(4, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k < N) {
                                int nxt = dsus[4].get(p + k);
                                auto[net1, net2] = meet(v, getid(4, nxt), dr);
                                if (same(4, v, getid(4, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(4, v, getid(4, p))) {
                        auto[met1, met2] = meet(v, getid(4, p), dr);
                        if (met2 >= ds) {
                            add(4, getid(4, p), met2, 3);
                        }
                    }
                }
                // 6, v, ds, 1
                {
                    int p = dsus[6].get(igr[3][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? (1 << i) : 1;
                        auto[met1, met2] = meet(v, getid(6, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k < N) {
                                int nxt = dsus[6].get(p + k);
                                auto[net1, net2] = meet(v, getid(6, nxt), dr);
                                if (same(6, v, getid(6, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(6, v, getid(6, p))) {
                        auto[met1, met2] = meet(v, getid(6, p), dr);
                        if (met2 >= ds) {
                            add(6, getid(6, p), met2, 1);
                        }
                    }
                }
            } else if (dr == 1) {
                // 4, v, ds, 2
                {
                    int p = dsus[4].get(igr[2][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? (1 << i) : 1;
                        auto[met1, met2] = meet(v, getid(4, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k < N) {
                                int nxt = dsus[4].get(p + k);
                                auto[net1, net2] = meet(v, getid(4, nxt), dr);
                                if (same(4, v, getid(4, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(4, v, getid(4, p))) {
                        auto[met1, met2] = meet(v, getid(4, p), dr);
                        if (met2 >= ds) {
                            add(4, getid(4, p), met2, 2);
                        }
                    }
                }
                // 2, v, ds, 3
                {
                    int p = dsus[2].get(igr[1][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? (1 << i) : 1;
                        auto[met1, met2] = meet(v, getid(2, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k < N) {
                                int nxt = dsus[2].get(p + k);
                                auto[net1, net2] = meet(v, getid(2, nxt), dr);
                                if (same(2, v, getid(2, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(2, v, getid(2, p))) {
                        auto[met1, met2] = meet(v, getid(2, p), dr);
                        if (met2 >= ds) {
                            add(2, getid(2, p), met2, 3);
                        }
                    }
                }
                // 7, v, ds, 0
                {
                    int p = dsus[7].get(igr[3][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? -(1 << i) : -1;
                        auto[met1, met2] = meet(v, getid(7, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k >= 0) {
                                int nxt = dsus[7].get(p + k);
                                auto[net1, net2] = meet(v, getid(7, nxt), dr);
                                if (same(7, v, getid(7, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(7, v, getid(7, p))) {
                        auto[met1, met2] = meet(v, getid(7, p), dr);
                        if (met2 >= ds) {
                            add(7, getid(7, p), met2, 0);
                        }
                    }
                }
            } else if (dr == 2) {
                // 7, v, ds, 3
                {
                    int p = dsus[7].get(igr[3][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? -(1 << i) : -1;
                        auto[met1, met2] = meet(v, getid(7, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k >= 0) {
                                int nxt = dsus[7].get(p + k);
                                auto[net1, net2] = meet(v, getid(7, nxt), dr);
                                if (same(7, v, getid(7, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(7, v, getid(7, p))) {
                        auto[met1, met2] = meet(v, getid(7, p), dr);
                        if (met2 >= ds) {
                            add(7, getid(7, p), met2, 3);
                        }
                    }
                }
                // 1, v, ds, 0
                {
                    int p = dsus[1].get(igr[0][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? -(1 << i) : -1;
                        auto[met1, met2] = meet(v, getid(1, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k >= 0) {
                                int nxt = dsus[1].get(p + k);
                                auto[net1, net2] = meet(v, getid(1, nxt), dr);
                                if (same(1, v, getid(1, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(1, v, getid(1, p))) {
                        auto[met1, met2] = meet(v, getid(1, p), dr);
                        if (met2 >= ds) {
                            add(1, getid(1, p), met2, 0);
                        }
                    }
                }
                // 5, v, ds, 1
                {
                    int p = dsus[5].get(igr[2][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? -(1 << i) : -1;
                        auto[met1, met2] = meet(v, getid(5, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k >= 0) {
                                int nxt = dsus[5].get(p + k);
                                auto[net1, net2] = meet(v, getid(5, nxt), dr);
                                if (same(5, v, getid(5, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(5, v, getid(5, p))) {
                        auto[met1, met2] = meet(v, getid(5, p), dr);
                        if (met2 >= ds) {
                            add(5, getid(5, p), met2, 1);
                        }
                    }
                }
            } else if (dr == 3) {
                // 5, v, ds, 0
                {
                    int p = dsus[5].get(igr[2][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? -(1 << i) : -1;
                        auto[met1, met2] = meet(v, getid(5, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k >= 0) {
                                int nxt = dsus[5].get(p + k);
                                auto[net1, net2] = meet(v, getid(5, nxt), dr);
                                if (same(5, v, getid(5, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(5, v, getid(5, p))) {
                        auto[met1, met2] = meet(v, getid(5, p), dr);
                        if (met2 >= ds) {
                            add(5, getid(5, p), met2, 0);
                        }
                    }
                }
                // 3, v, ds, 1
                {
                    int p = dsus[3].get(igr[1][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? -(1 << i) : -1;
                        auto[met1, met2] = meet(v, getid(3, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k >= 0) {
                                int nxt = dsus[3].get(p + k);
                                auto[net1, net2] = meet(v, getid(3, nxt), dr);
                                if (same(3, v, getid(3, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(3, v, getid(3, p))) {
                        auto[met1, met2] = meet(v, getid(3, p), dr);
                        if (met2 >= ds) {
                            add(3, getid(3, p), met2, 1);
                        }
                    }
                }
                // 6, v, ds, 2
                {
                    int p = dsus[6].get(igr[3][v]);
                    for (int i = 17; i >= -1; --i) {
                        int k = i >= 0 ? (1 << i) : 1;
                        auto[met1, met2] = meet(v, getid(6, p), dr);
                        if (met1 == -1 || met2 < ds) {
                            if (p + k < N) {
                                int nxt = dsus[6].get(p + k);
                                auto[net1, net2] = meet(v, getid(6, nxt), dr);
                                if (same(6, v, getid(6, nxt))) {  
                                    if (i == -1 || (net1 == -1 || net2 < ds)) {
                                        p = nxt;
                                    }
                                }
                            }
                        }
                    }
                    if (same(6, v, getid(6, p))) {
                        auto[met1, met2] = meet(v, getid(6, p), dr);
                        if (met2 >= ds) {
                            add(6, getid(6, p), met2, 2);
                        }
                    }
                }
            } else {
                assert(false);
            }
        };
        add(0, 0, 0, 0);
        while (true) {
            std::pair<int, int> x = {MAX, -1};
            for (int i = 0; i < 8; ++i) {
                while (!pqs[i].empty() && vis[pqs[i].top().second]) {
                    add_next(i, pqs[i].top().second);
                    pqs[i].pop();
                }
                if (!pqs[i].empty()) {
                    x = std::min(x, pqs[i].top());
                }
            }
            if (x.second == -1) {
                break;
            }
            for (int i = 0; i < 8; ++i) {
                if (!pqs[i].empty() && pqs[i].top() == x) {
                    pqs[i].pop();
                    int v = x.second;
                    add_next(i, v);
                    vis[v] = true;
                    debug(v, dis[i][v], dir[i][v], A[v]);
                    jump_nexts(v, dis[i][v], dir[i][v]);
                    break;
                }
            }
        }
        debug(vis);
        ans = std::max(ans, std::accumulate(vis.begin(), vis.end(), 0));
    };

    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < N; ++j) {
            debug(j, A[j]);
        }
        work();
        for (int j = 0; j < N; ++j) {
            std::tie(A[j][0], A[j][1]) = std::make_pair(-A[j][1], A[j][0]);
        }
        debug();
    }

    std::cout << ans << '\n';

    return 0;
};
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...