제출 #367990

#제출 시각아이디문제언어결과실행 시간메모리
367990KoDFun Tour (APIO20_fun)C++17
100 / 100
370 ms21732 KiB
#include "fun.h"

#include <vector>
#include <algorithm>
#include <iostream>

template <class T>
using Vec = std::vector<T>;

Vec<int> createFunTour(int N, int Q) {
    // Step 1. find centroid (N-1 queries)
    int centroid = 0;
    Vec<int> subtree(N);
    subtree[0] = N;
    for (int i = 1; i < N; ++i) {
        subtree[i] = attractionsBehind(0, i);
        if (subtree[i] * 2 >= N && subtree[i] < subtree[centroid]) {
            centroid = i;
        }
    }
    // Step 2. compute distances from the centroid (N-1 queries)
    Vec<int> dist(N);
    for (int i = 0; i < N; ++i) {
        if (i != centroid) {
            dist[i] = hoursRequired(centroid, i);
        }
    }
    // Step 3. find direct children of the centroid (0 queries)
    Vec<int> children;
    for (int i = 0; i < N; ++i) {
        if (dist[i] == 1) {
            children.push_back(i);
        }
    }
    // Step 4. classify vertices (at most 2N-2 queries)
    Vec<int> belong(N, (int) children.size() - 1);
    for (int i = 0; i < (int) children.size() - 1; ++i) {
        const auto root = children[i];
        for (int u = 0; u < N; ++u) {
            if (u != centroid && dist[u] > hoursRequired(root, u)) {
                belong[u] = i;
            }
        }
    }
    // Step 5. construct a fun tour (0 queries)
    Vec<int> ret;
    ret.reserve(N);
    Vec<Vec<int>> vertices(children.size());
    for (int i = 0; i < N; ++i) {
        if (i != centroid) {
            vertices[belong[i]].push_back(i);
        }
    }
    for (auto &vec: vertices) {
        std::sort(vec.begin(), vec.end(), [&](const int i, const int j) {
            return dist[i] < dist[j];
        });
    }
    const auto farthest = [&](const int i) {
        return vertices[i].empty() ? -1 : dist[vertices[i].back()];
    };
    const auto select_max = [&](const int avoid) {
        int select = -1, score = -1;
        for (int i = 0; i < (int) children.size(); ++i) {
            if (i != avoid) {
                const auto tmp = farthest(i);
                if (score < tmp) {
                    select = i;
                    score = tmp;
                }
            }
        }
        return select;
    };
    int pivot = -1, last = -1, remain = N;
    while (true) {
        for (int i = 0; i < (int) children.size(); ++i) {
            if (2 * ((int) vertices[i].size()) == remain) {
                pivot = i;
            }
        }
        if (pivot != -1) {
            break;
        }
        const auto select = select_max(last);
        ret.push_back(vertices[select].back());
        vertices[select].pop_back();
        last = select;
        remain -= 1;
    }
    if (ret.size() >= 2) {
        const auto u = ret[ret.size() - 1];
        const auto v = ret[ret.size() - 2];
        if (belong[v] != pivot && dist[v] > dist[u]) {
            ret.pop_back();
            vertices[belong[u]].push_back(u);
        }
    }
    while (true) {
        if (vertices[pivot].empty()) {
            break;
        }
        ret.push_back(vertices[pivot].back());
        vertices[pivot].pop_back();
        const auto select = select_max(pivot);
        if (select == -1) {
            break;
        }
        ret.push_back(vertices[select].back());
        vertices[select].pop_back();
    }
    ret.push_back(centroid);
    return ret;
}
#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...