Submission #1274836

#TimeUsernameProblemLanguageResultExecution timeMemory
1274836mehrzadMigrations (IOI25_migrations)C++17
10 / 100
30 ms1028 KiB
#include "migrations.h" #include <vector> #include <utility> #include <algorithm> /* Robust diameter-in-a-tree strategy (works for general case): First run (send_message): - Build the tree online since P[i] < i and i increases. - Maintain binary lifting table up[LOG][v] with root 0 having up[k][0] = 0 (so we never use -1 and avoid out-of-bounds during LCA). - Track depths. - Maintain current diameter endpoints (A, B) and its length D: * For each new node i, compute dist(i, A) and dist(i, B). * If dist(i, A) > D => (B = i, D = dist(i, A)). else if dist(i, B) > D => (A = i, D = dist(i, B)). - Send exactly TWO messages (≤ 50 and values ≤ N ≤ 10000 ≤ 20000): * at i == N-2: send A+1 * at i == N-1: send B+1 Second run (longest_path): - Read the last two non-zero S entries: penultimate => A+1, last => B+1. - Return (A, B). Fix vs previous attempt: - We now keep up[k][0] = 0 for all k and set up via up[k][v] = up[k-1][ up[k-1][v] ]. This avoids ever assigning -1 and eliminates potential out-of-bounds in LCA, which could cause an off-by-one error in the diameter on adversarial trees. */ namespace { constexpr int MAXN = 10000 + 5; constexpr int LOG = 15; // 2^14 = 16384 > 10000 static bool initialized = false; static int depth_arr[MAXN]; static int up[LOG][MAXN]; // up[k][v] = 2^k-th ancestor (root-sticky) static int A = 0, B = 0; // current diameter endpoints static int D = 0; // current diameter length inline int lca(int u, int v) { if (depth_arr[u] < depth_arr[v]) std::swap(u, v); int diff = depth_arr[u] - depth_arr[v]; for (int k = 0; k < LOG; ++k) if (diff & (1 << k)) u = up[k][u]; if (u == v) return u; for (int k = LOG - 1; k >= 0; --k) { if (up[k][u] != up[k][v]) { u = up[k][u]; v = up[k][v]; } } return up[0][u]; } inline int dist(int u, int v) { int w = lca(u, v); return depth_arr[u] + depth_arr[v] - 2 * depth_arr[w]; } inline void add_node(int i, int p) { // depth depth_arr[i] = depth_arr[p] + 1; // ancestors (root-sticky) up[0][i] = p; for (int k = 1; k < LOG; ++k) { up[k][i] = up[k - 1][ up[k - 1][i] ]; } // attempt to extend diameter int dA = dist(i, A); if (dA > D) { B = i; D = dA; return; } int dB = dist(i, B); if (dB > D) { A = i; D = dB; return; } } } // Research team: called N-1 times with i = 1..N-1 int send_message(int N, int i, int Pi) { if (!initialized) { initialized = true; // Root initialization depth_arr[0] = 0; for (int k = 0; k < LOG; ++k) up[k][0] = 0; // Start with trivial diameter A = 0; B = 0; D = 0; } // Add the current node add_node(i, Pi); // Send two messages only at the last two indices if (i == N - 2) return A + 1; // encode A in [1..N] if (i == N - 1) return B + 1; // encode B in [1..N] return 0; } // Museum: called once in the second run std::pair<int,int> longest_path(std::vector<int> S) { int N = (int)S.size(); int last = -1, penult = -1; for (int i = 1; i < N; ++i) { if (S[i] != 0) { penult = last; last = i; } } if (last == -1) { // No messages (shouldn't happen with our sender); fallback return {0, 0}; } if (penult == -1) { // Only one message; fallback assuming one endpoint is 0 int b = S[last] - 1; if (b < 0) b = 0; return {0, b}; } int a = S[penult] - 1; int b = S[last] - 1; if (a < 0) a = 0; if (b < 0) b = 0; return {a, b}; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...