Submission #1275580

#TimeUsernameProblemLanguageResultExecution timeMemory
1275580mehrzadMigrations (IOI25_migrations)C++17
0 / 100
30 ms1080 KiB
#include "migrations.h"
#include <bits/stdc++.h>
using namespace std;

/*
Goal: Z ≤ 4, M ≈ 15–20, correctness guaranteed.

Protocol (tail-window streaming):
- Reserve a window of size W at the end (W >= 1 + 14 = 15; we use W = 20 for slack).
- At i == N - W      : send RESET (= 4).
- For i in (N - W + 1) .. (N - 1):
    * Track online diameter endpoints (A,B).
    * If (A,B) changed since the last emitted digit → send RESET (=4), mark a new stream start.
    * Else emit the next base-4 digit of U and V interleaved, LSB-first:
        order: u0, v0, u1, v1, ..., u6, v6  (14 digits total)
      The digit positions wrap if the stream restarts.
- Outside the window: send 0.

Museum decoding:
- From the tail window, take digits after the LAST reset (value 4).
- Read the LAST 14 digits after that reset; interleaved LSB-first, reconstruct U and V.
- If there are fewer than 14 digits (very small N), pad missing high digits with 0.
*/

namespace {
    // globals per test
    bool inited = false;
    int Nglob = 0, LOGv = 0;
    const int W = 20;                 // tail window size (tune: 20–32)
    int startTail = 1;                // N - W
    // tree lifting
    vector<int> depth;
    vector<vector<int>> up;
    // diameter state
    int A = 0, B = 0, D = 0;
    // streaming state
    int stream_pos = -1;              // -1 means not streaming yet; else 0..13
    int lastA = 0, lastB = 0;         // to detect changes
    bool streaming = false;
    // helpers
    inline void reset_test(int N){
        inited = true;
        Nglob = N;
        LOGv = 0; while ((1<<LOGv) <= max(1,Nglob)) ++LOGv;
        depth.assign(Nglob, 0);
        up.assign(Nglob, vector<int>(LOGv, 0));
        for (int k=0;k<LOGv;++k) up[0][k]=0;
        A=B=0; D=0;
        startTail = max(1, Nglob - W);
        stream_pos = -1;
        lastA = lastB = 0;
        streaming = false;
    }
    inline int lca(int u,int v){
        if (depth[u]<depth[v]) swap(u,v);
        int diff = depth[u]-depth[v];
        for (int k=0; diff; ++k, diff>>=1) if (diff&1) u=up[u][k];
        if (u==v) return u;
        for (int k=LOGv-1;k>=0;--k) if (up[u][k]!=up[v][k]){ u=up[u][k]; v=up[v][k]; }
        return up[u][0];
    }
    inline int dist(int u,int v){
        int w=lca(u,v);
        return depth[u]+depth[v]-2*depth[w];
    }
    inline int get_digit_base4(int x, int d){ // d-th digit, LSB-first
        return (x >> (2*d)) & 3; // since base-4 digit = 2 bits
    }
}

int send_message(int N, int i, int Pi){
    if (!inited || i==1) reset_test(N);

    // build lifting
    depth[i] = depth[Pi] + 1;
    up[i][0] = Pi;
    for (int k=1;k<LOGv;++k) up[i][k] = up[ up[i][k-1] ][k-1];

    // update diameter
    int dA = dist(i,A), dB = dist(i,B);
    if (dA > D){ B = i; D = dA; }
    else if (dB > D){ A = i; D = dB; }

    // default silent
    int out = 0;

    if (i == N - W){
        // force a reset: start of tail window
        out = 4;               // RESET marker (Z ≤ 4 holds)
        streaming = false;
        stream_pos = -1;
        lastA = A; lastB = B;
    } else if (i > N - W){
        // inside tail window
        bool changed = (A != lastA) || (B != lastB);
        if (changed){
            out = 4;           // RESET
            streaming = false;
            stream_pos = -1;
            lastA = A; lastB = B;
        } else {
            // continue / start streaming digits for (A,B)
            if (!streaming){ streaming = true; stream_pos = 0; }
            int digit;
            if (stream_pos < 14){
                // interleaved u0,v0,u1,v1,...
                int which = stream_pos;
                if (which % 2 == 0){
                    int du = which/2;
                    digit = get_digit_base4(A, du);
                } else {
                    int dv = which/2;
                    digit = get_digit_base4(B, dv);
                }
            } else {
                // extra digits (if any) harmless; send 0 to stay in Z ≤ 4
                digit = 0;
            }
            out = digit + 1;   // map {0,1,2,3} -> {1,2,3,4}
            ++stream_pos;
        }
    }

    return out; // 0 outside window; 1..4 inside
}

std::pair<int,int> longest_path(std::vector<int> S){
    int N = (int)S.size();
    int tailStart = max(1, N - 20); // must match W in send_message
    // Find the last reset (=4) in the tail window
    int lastReset = -1;
    for (int i = N-1; i >= tailStart; --i){
        if (S[i] == 4) { lastReset = i; break; }
    }
    // Collect digits after last reset
    vector<int> digs; digs.reserve(20);
    for (int i = max(tailStart, lastReset+1); i < N; ++i){
        int v = S[i];
        if (v >= 1 && v <= 4) digs.push_back(v-1); // base-4 digit
    }
    // We need the last 14 digits after the last reset.
    while ((int)digs.size() < 14) digs.push_back(0); // pad if tiny N
    // Take the last 14
    vector<int> last14(digs.end()-14, digs.end());
    // Reconstruct A and B from interleaved LSB-first digits
    int A = 0, B = 0;
    for (int pos = 0; pos < 14; ++pos){
        int d = last14[pos];
        if (pos % 2 == 0){ // A digit
            int k = pos/2;
            A |= (d << (2*k));
        } else { // B digit
            int k = pos/2;
            B |= (d << (2*k));
        }
    }
    // Clamp to [0, N-1]
    if (A >= N) A = N-1;
    if (B >= N) B = N-1;
    return {A, B};
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...