제출 #1368194

#제출 시각아이디문제언어결과실행 시간메모리
1368194sagnbaevvMigrations (IOI25_migrations)C++20
100 / 100
28 ms1292 KiB
#include <bits/stdc++.h>
#include "migrations.h"
using namespace std;

namespace {
    const int MAXN = 10000 + 5;
    const int LOG = 15;

    // Internal labels are 1-based.
    // Original site v corresponds to internal vertex v + 1.

    const int B[7] = {0, 33, 9, 5, 3, 3, 0};
    const int E[7] = {0, 9828, 9968, 9988, 9994, 9996, 9998};

    const int F[5][5] = {
        {0, 1, 4, 5, 6},
        {1, 0, 7, 8, 6},
        {2, 3, 8, 4, 5},
        {6, 7, 2, 3, 8},
        {8, 3, 4, 5, 7}
    };

    const int G[5][3] = {
        {2, 0, 3},
        {0, 4, 5},
        {2, 5, 3},
        {2, 1, 3},
        {0, 5, 1}
    };

    int curN = -1;

    int up[MAXN][LOG];
    int depth_[MAXN];

    int diaX, diaY, diaLen;

    vector<int> candX, candY;
    int bucketX[MAXN], bucketY[MAXN];

    int codeState;
    int point[10], point2[6];

    bool same_edge(int a, int b, int c, int d) {
        return min(a, b) == min(c, d) && max(a, b) == max(c, d);
    }

    void init_sender(int N) {
        curN = N;

        for (int i = 0; i <= N + 1; ++i) {
            depth_[i] = 0;
            bucketX[i] = bucketY[i] = 0;
            for (int k = 0; k < LOG; ++k) up[i][k] = 1;
        }

        for (int k = 0; k < LOG; ++k) up[1][k] = 1;

        diaX = diaY = 1;
        diaLen = 0;

        candX.clear();
        candY.clear();

        codeState = 0;
    }

    int lca(int a, int b) {
        if (depth_[a] < depth_[b]) swap(a, b);

        int diff = depth_[a] - depth_[b];
        for (int k = 0; k < LOG; ++k) {
            if ((diff >> k) & 1) a = up[a][k];
        }

        if (a == b) return a;

        for (int k = LOG - 1; k >= 0; --k) {
            if (up[a][k] != up[b][k]) {
                a = up[a][k];
                b = up[b][k];
            }
        }

        return up[a][0];
    }

    int dist_tree(int a, int b) {
        int c = lca(a, b);
        return depth_[a] + depth_[b] - 2 * depth_[c];
    }

    void update_diameter(int z) {
        int dx = dist_tree(diaX, z);
        int dy = dist_tree(z, diaY);

        diaLen = max({diaLen, dx, dy});

        // Ties are allowed. We only need any valid diameter.
        if (diaLen == dx) {
            diaY = z;
        } else if (diaLen == dy) {
            diaX = z;
        }
    }

    void shrink_to_actual_buckets() {
        vector<int> nx, ny;

        for (int v : candX) {
            if (bucketX[v] == bucketX[diaX]) nx.push_back(v);
        }

        for (int v : candY) {
            if (bucketY[v] == bucketY[diaY]) ny.push_back(v);
        }

        candX.swap(nx);
        candY.swap(ny);
    }

    void add_block_and_partition(int b) {
        for (int v = E[b - 1] + 1; v <= E[b]; ++v) {
            candX.push_back(v);
            candY.push_back(v);
            update_diameter(v);
        }

        int sx = (int)candX.size();
        int sy = (int)candY.size();

        int px = 0, py = 0;

        for (int c = 0; c < B[b]; ++c) {
            int tx = px + sx / B[b] + (c < sx % B[b]);
            while (px < tx) {
                bucketX[candX[px++]] = c;
            }

            int ty = py + sy / B[b] + (c < sy % B[b]);
            while (py < ty) {
                bucketY[candY[py++]] = c;
            }
        }

        if (b == 1) {
            // First block encodes an unordered bucket pair.
            if (diaX < diaY) swap(diaX, diaY);
            codeState = bucketX[diaX] * (bucketX[diaX] + 1) / 2 + bucketY[diaY];
        } else {
            codeState = bucketX[diaX] * B[b] + bucketY[diaY];
        }
    }
}

int send_message(int N, int i, int Pi) {
    if (i == 1 || curN != N) init_sender(N);

    int u = i + 1;
    int p = Pi + 1;

    depth_[u] = depth_[p] + 1;
    up[u][0] = p;

    for (int k = 1; k < LOG; ++k) {
        up[u][k] = up[up[u][k - 1]][k - 1];
    }

    for (int b = 1; b <= 5; ++b) {
        if (u == E[b + 1]) {
            shrink_to_actual_buckets();
        }

        if (u == E[b]) {
            add_block_and_partition(b);
        }

        if (E[b] <= u && u < E[b + 1]) {
            if (codeState != 0 && (codeState - 1) / 4 == u - E[b]) {
                return (codeState - 1) % 4 + 1;
            }
        }
    }

    // Last three special transmissions.

    if (u == N - 2) {
        candX.push_back(u - 1);
        candX.resize(4, u);

        candY.push_back(u - 1);
        candY.resize(4, u);

        update_diameter(u - 1);
        update_diameter(u);

        for (int t = 0; t < 4; ++t) {
            point[t] = candX[t];
            point[t + 4] = candY[t];
        }
        point[8] = u;

        for (int c = 0; c < 5; ++c) {
            for (int a = 0; a < 2; ++a) {
                for (int b = 2; b < 5; ++b) {
                    if (a == 0 || b < 4) {
                        if (same_edge(diaX, diaY, point[F[c][a]], point[F[c][b]])) {
                            codeState = c;
                            return c;
                        }
                    }
                }
            }
        }
    }

    if (u == N - 1) {
        update_diameter(u);

        point2[5] = u;
        for (int t = 0; t < 5; ++t) {
            point2[t] = point[F[codeState][t]];
        }

        for (int c = 0; c < 5; ++c) {
            for (int a = 0; a < 2; ++a) {
                if (same_edge(diaX, diaY, point2[G[c][a]], point2[G[c][a + 1]])) {
                    codeState = c;
                    return c;
                }
            }
        }
    }

    if (u == N) {
        update_diameter(u);

        point[3] = u;
        for (int t = 0; t < 3; ++t) {
            point[t] = point2[G[codeState][t]];
        }

        int k = 0;

        for (int a = 0; a < 4; ++a) {
            for (int b = a + 1; b < 4; ++b) {
                if (a == 0 && b == 2) continue;

                if (same_edge(diaX, diaY, point[a], point[b])) {
                    return k;
                }

                ++k;
            }
        }
    }

    return 0;
}

pair<int,int> longest_path(vector<int> S) {
    int N = (int)S.size();

    vector<int> a(N + 1, 0);
    for (int u = 1; u <= N; ++u) {
        a[u] = S[u - 1];
    }

    vector<int> X, Y;

    static int bx[MAXN], by[MAXN];

    for (int b = 1; b <= 5; ++b) {
        for (int v = E[b - 1] + 1; v <= E[b]; ++v) {
            X.push_back(v);
            Y.push_back(v);
        }

        int sx = (int)X.size();
        int sy = (int)Y.size();

        int px = 0, py = 0;

        for (int c = 0; c < B[b]; ++c) {
            int tx = px + sx / B[b] + (c < sx % B[b]);
            while (px < tx) {
                bx[X[px++]] = c;
            }

            int ty = py + sy / B[b] + (c < sy % B[b]);
            while (py < ty) {
                by[Y[py++]] = c;
            }
        }

        int h = 0;
        int hx = 0;
        int hy = 0;

        for (int u = E[b]; u < E[b + 1]; ++u) {
            if (a[u] != 0) {
                h = (u - E[b]) * 4 + a[u];
            }
        }

        if (b == 1) {
            for (int i = 0; i < B[b]; ++i) {
                for (int j = 0; j <= i; ++j) {
                    if (i * (i + 1) / 2 + j == h) {
                        hx = i;
                        hy = j;
                    }
                }
            }
        } else {
            hx = h / B[b];
            hy = h % B[b];
        }

        vector<int> nX, nY;

        for (int v : X) {
            if (bx[v] == hx) nX.push_back(v);
        }

        for (int v : Y) {
            if (by[v] == hy) nY.push_back(v);
        }

        X.swap(nX);
        Y.swap(nY);
    }

    X.push_back(N - 3);
    X.resize(4, N - 2);

    Y.push_back(N - 3);
    Y.resize(4, N - 2);

    int p[9], q[6], r[4];

    for (int t = 0; t < 4; ++t) {
        p[t] = X[t];
        p[t + 4] = Y[t];
    }
    p[8] = N - 2;

    q[5] = N - 1;
    for (int t = 0; t < 5; ++t) {
        q[t] = p[F[a[N - 2]][t]];
    }

    r[3] = N;
    for (int t = 0; t < 3; ++t) {
        r[t] = q[G[a[N - 1]][t]];
    }

    int code = a[N];
    int k = 0;

    for (int i = 0; i < 4; ++i) {
        for (int j = i + 1; j < 4; ++j) {
            if (i == 0 && j == 2) continue;

            if (k == code) {
                return {r[i] - 1, r[j] - 1};
            }

            ++k;
        }
    }

    return {0, 0};
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…