#include "migrations.h"
#include <bits/stdc++.h>
using namespace std;
#define forsn(i, s, n) for (int i = int(s); i < int(n); i++)
#define forn(i, n) forsn(i, 0, n)
#define dforsn(i, s, n) for (int i = int(n) - 1; i >= int(s); i--)
#define dforn(i, n) dforsn(i, 0, n)
using vi = vector<int>;
using ll = long long;
using ii = pair<int, int>;
#define fst first
#define snd second
#define sz(x) int(x.size())
#define all(x) begin(x), end(x)
#define pb push_back
#define eb emplace_back
const int N = 10000, K = 15;
int up[K][N], depth[N];
int lca(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    int diff = depth[u] - depth[v];
    forn(i, K) if (diff >> i & 1) u = up[i][u];
    if (u == v) return u;
    dforn(i, K) if (up[i][u] != up[i][v]) {
        u = up[i][u], v = up[i][v];
    }
    assert(up[0][u] == up[0][v]);
    return up[0][u];
}
int dist(int u, int v) {
    return depth[u] + depth[v] - 2 * depth[lca(u, v)];
}
const int MOVES = 8;
const int B[MOVES] = {140, 20, 6, 2, 2, 1, 1, 1};
const int T[MOVES] = {0,   1, 1, 1, 1, 2, 3, 4};
int D[MOVES];
int u, v;
vi candidatesU, candidatesV;
vector<ii> candidatesDiameter;
int indice, value;
void reduce(vi &c, int v, int l) {
    vi new_c;
    forn(i, sz(c)) {
        if (i / l == v) new_c.pb(c[i]);
    }
    c = new_c;
}
int getBase(int g) {
    if (T[g] == 1) {
        int base = 1;
        while ((base + 1) * (base + 1) <= B[g] * 4 + 1) base++;
        return base;
    } else if (T[g] == 0) {
        int base = 1;
        while ((base + 2) * (base + 1) / 2 <= B[g] * 4 + 1) base++;
        return base;
    }
    assert(false);
}
void send(int number) {
    if (number == -1) {
        indice = 0, value = 0;
    } else {
        indice = number / 4;
        value = number % 4 + 1;
    }
}
vector<ii> partitions[5] = {
    {{0, 4}, {1, 4}, {0, 5}, {1, 5}, {0, 6}},
    {{0, 7}, {1, 7}, {0, 8}, {1, 8}, {1, 6}},
    {{2, 4}, {2, 5}, {3, 4}, {3, 5}, {8, 4}},
    {{2, 6}, {2, 8}, {3, 7}, {2, 7}, {3, 8}},
    {{8, 6}, {8, 7}, {8, 5}, {3, 5}, {3, 6}}
};
bool contains(int p, ii diameter) {
    for (auto x : partitions[p]) if (diameter == x) return true;
    return false;
}
vi getCandidates() {
    vi candidates;
    for (auto [U, V] : candidatesDiameter) {
        candidates.pb(U);
        candidates.pb(V);
    }
    sort(all(candidates));
    candidates.erase(unique(all(candidates)), end(candidates));
    return candidates;
}
int send_message(int /*N*/, int i, int Pi) {
    if (i == 1) {
        depth[0] = 0;
        forn(j, K) up[j][0] = 0; 
        u = 0, v = 0;
        candidatesU.pb(0), candidatesV.pb(0);
        D[MOVES - 1] = B[MOVES - 1];
        dforn(j, MOVES - 1) D[j] = D[j + 1] + B[j];
    }
    up[0][i] = Pi, depth[i] = depth[Pi] + 1;
    forn(j, K - 1) up[j + 1][i] = up[j][up[j][i]];
    if (dist(i, u) > dist(u, v)) v = i;
    else if (dist(i, v) > dist(u, v)) u = i;
    candidatesU.pb(i), candidatesV.pb(i);
    if (i <= N - D[0] && u > v) swap(u, v);
    if (i < N - D[0]) return 0;
    forn(g, MOVES) if (i == N - D[g]) {
        int idxU = 0, idxV = 0;
        while (candidatesU[idxU] != u) idxU++;
        while (candidatesV[idxV] != v) idxV++;
        if (T[g] <= 1) {
            int base = getBase(g);
            int lenU = (sz(candidatesU) + base - 1) / base;
            int lenV = (sz(candidatesV) + base - 1) / base;
            int sectionU = idxU / lenU; assert(sectionU < base);
            int sectionV = idxV / lenV; assert(sectionV < base);
            reduce(candidatesU, sectionU, lenU);
            reduce(candidatesV, sectionV, lenV);
            if (T[g] == 0) {
                assert(sectionU <= sectionV);
                assert(base * (base + 1) / 2 <= B[g] * 4 + 1);
                send(sectionV * (sectionV + 1) / 2 + sectionU - 1);
            } else {
                send(sectionU * base + sectionV - 1);
            }
        } else if (T[g] == 2) {
            while (sz(candidatesU) < 5) candidatesU.pb(candidatesU.back());
            while (sz(candidatesV) < 5) candidatesV.pb(candidatesV.back());
            int idx = 0;
            ii diameter = {idxU == 4 ? 8 : idxU, idxV + 4};
            while (!contains(idx, diameter)) idx++;
            for (auto [a, b] : partitions[idx]) {
                candidatesDiameter.eb(candidatesU[a == 8 ? 4 : a], candidatesV[b - 4]);
            }
            indice = 0, value = idx;
        } else if (T[g] == 3) {
            vi candidates = getCandidates();
            while (sz(candidates) < 5) candidates.pb(candidates.back());
            int shared = candidatesDiameter.back().fst;
            candidatesDiameter.eb(shared, i);
            for (int x : candidates) if (x != shared) {
                candidatesDiameter.eb(x, i);
            }
            while (sz(candidatesDiameter) < 10) candidatesDiameter.pb(candidatesDiameter.back());
            int idx = 0;
            while (ii{u, v} != candidatesDiameter[idx] &&
                   ii{v, u} != candidatesDiameter[idx]) idx++;
            candidatesDiameter = {candidatesDiameter[idx], candidatesDiameter[idx ^ 1]};       
            assert(candidatesDiameter[0].fst == candidatesDiameter[1].fst ||
                   candidatesDiameter[0].fst == candidatesDiameter[1].snd ||
                   candidatesDiameter[0].snd == candidatesDiameter[1].snd ||
                   candidatesDiameter[0].snd == candidatesDiameter[1].fst);
            indice = 0, value = idx / 2;
        } else if (T[g] == 4) {
            vi candidates = getCandidates();
            while (sz(candidates) < 3) candidates.pb(candidates.back());
            for (int x : candidates) candidatesDiameter.eb(x, i);
            sort(all(candidatesDiameter));
            int idx = 0;
            while (ii{u, v} != candidatesDiameter[idx] &&
                   ii{v, u} != candidatesDiameter[idx]) idx++;
            indice = 0, value = idx;
        }
    }
    forn(g, MOVES) if (i == N - D[g] + indice) return value;
    return 0;
}
ii longest_path(vi S) {
    D[MOVES - 1] = B[MOVES - 1];
    dforn(j, MOVES - 1) D[j] = D[j + 1] + B[j];
    candidatesU.clear(), candidatesV.clear();
    candidatesDiameter.clear();
    forn(i, N) {
        candidatesU.pb(i), candidatesV.pb(i);
        forn(g, MOVES) if (i == N - D[g]) {
            if (T[g] <= 1) {
                indice = 0, value = 0;
                forsn(j, i, i + B[g]) if (S[j]) {
                    indice = j - i;
                    value = S[j];
                }
                int base = getBase(g);
                int lenU = (sz(candidatesU) + base - 1) / base;
                int lenV = (sz(candidatesV) + base - 1) / base;
                int number = value == 0 ? -1 : indice * 4 + (value - 1);
                number++;
                int sectionU, sectionV;
                if (T[g] == 0) {
                    sectionV = 0;
                    while ((sectionV + 1) * (sectionV + 2) / 2 <= number) sectionV++;
                    sectionU = number - sectionV * (sectionV + 1) / 2;
                } else {
                    sectionU = number / base, sectionV = number % base;
                }
                reduce(candidatesU, sectionU, lenU);
                reduce(candidatesV, sectionV, lenV);
            } else if (T[g] == 2) {
                while (sz(candidatesU) < 5) candidatesU.pb(candidatesU.back());
                while (sz(candidatesV) < 5) candidatesV.pb(candidatesV.back());
                int idx = S[i];
                for (auto [a, b] : partitions[idx]) {
                    candidatesDiameter.eb(candidatesU[a == 8 ? 4 : a], candidatesV[b - 4]);
                }
            } else if (T[g] == 3) {
                vi candidates = getCandidates();
                while (sz(candidates) < 5) candidates.pb(candidates.back());
                int shared = candidatesDiameter.back().fst;
                candidatesDiameter.eb(shared, i);
                for (int x : candidates) if (x != shared) {
                    candidatesDiameter.eb(x, i);
                }
                while (sz(candidatesDiameter) < 10) candidatesDiameter.pb(candidatesDiameter.back());
                int idx = S[i];
                candidatesDiameter = {
                    candidatesDiameter[2 * idx],
                    candidatesDiameter[2 * idx + 1]
                };
            } else if (T[g] == 4) {
                vi candidates = getCandidates();
                while (sz(candidates) < 3) candidates.pb(candidates.back());
                for (int x : candidates) candidatesDiameter.eb(x, i);
                sort(all(candidatesDiameter));
                return candidatesDiameter[S[i]];
            }
        }
    }
    assert(false);
}
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |