Submission #1159976

#TimeUsernameProblemLanguageResultExecution timeMemory
1159976jus_tengVillage (BOI20_village)C++20
0 / 100
1095 ms327680 KiB
#include <bits/stdc++.h>
using namespace std;

int numberOfHouses, logLevel;
vector<vector<int>> adjacencyList;
vector<long long> depth;
vector<vector<int>> up;
vector<int> timeIn, timeOut;
long long timer;

void depthFirstSearch(int vertex, int parent) {
    timeIn[vertex] = ++timer;
    up[vertex][0] = parent;
    depth[vertex] = (parent == vertex) ? 0 : depth[parent] + 1;
    for (int i = 1; i <= logLevel; ++i) {
        up[vertex][i] = up[up[vertex][i-1]][i-1];
    }
    for (int neighbor : adjacencyList[vertex]) {
        if (neighbor != parent) {
            depthFirstSearch(neighbor, vertex);
        }
    }
    timeOut[vertex] = ++timer;
}

bool isAncestor(int ancestor, int descendant) {
    return timeIn[ancestor] <= timeIn[descendant] && timeOut[ancestor] >= timeOut[descendant];
}

int lowestCommonAncestor(int node1, int node2) {
    if (isAncestor(node1, node2)) return node1;
    if (isAncestor(node2, node1)) return node2;
    for (int i = logLevel; i >= 0; --i) {
        if (!isAncestor(up[node1][i], node2)) {
            node1 = up[node1][i];
        }
    }
    return up[node1][0];
}

long long calculateDistance(int node1, int node2) {
    int lca = lowestCommonAncestor(node1, node2);
    return depth[node1] + depth[node2] - 2 * depth[lca];
}

void preprocessTree(int root) {
    timeIn.resize(numberOfHouses);
    timeOut.resize(numberOfHouses);
    depth.resize(numberOfHouses);
    timer = 0;
    logLevel = ceil(log2(numberOfHouses));
    up.assign(numberOfHouses, vector<int>(logLevel + 1));
    depthFirstSearch(root, root);
}

pair<int, int> findFarthestNode(int start) {
    vector<long long> distances(numberOfHouses, -1);
    queue<int> q;
    q.push(start);
    distances[start] = 0;
    int farthest = start;
    while (!q.empty()) {
        int current = q.front();
        q.pop();
        for (int neighbor : adjacencyList[current]) {
            if (distances[neighbor] == -1) {
                distances[neighbor] = distances[current] + 1;
                q.push(neighbor);
                if (distances[neighbor] > distances[farthest]) {
                    farthest = neighbor;
                }
            }
        }
    }
    return {farthest, distances[farthest]};
}

vector<int> getDiameter() {
    auto [nodeA, _] = findFarthestNode(0);
    auto [nodeB, diameter] = findFarthestNode(nodeA);
    vector<int> path;
    int current = nodeB;
    while (current != nodeA) {
        path.push_back(current);
        current = up[current][0];
    }
    path.push_back(nodeA);
    return path;
}

long long findTotalLength(const vector<int>& oldHouses, const vector<int>& newHouses) {
    long long total = 0;
    for (int i = 0; i < numberOfHouses; ++i) {
        total += calculateDistance(oldHouses[i], newHouses[i]);
    }
    return total;
}

void findMinMaxAssignments(vector<int>& minAssignment, vector<int>& maxAssignment, long long& minTotal, long long& maxTotal) {
    vector<int> oldHouses(numberOfHouses);
    for (int i = 0; i < numberOfHouses; ++i) oldHouses[i] = i;

    minTotal = LLONG_MAX;
    vector<int> perm(numberOfHouses);
    iota(perm.begin(), perm.end(), 0);
    do {
        long long currentTotal = findTotalLength(oldHouses, perm);
        if (currentTotal < minTotal) {
            minTotal = currentTotal;
            minAssignment = perm;
        }
    } while (next_permutation(perm.begin(), perm.end()));

    vector<int> diameter = getDiameter();
    int diameterSize = diameter.size();
    maxTotal = 0;
    for (int i = 0; i < numberOfHouses; ++i) {
        maxAssignment[i] = diameter[(i + diameterSize / 2) % diameterSize];
        maxTotal += calculateDistance(i, maxAssignment[i]);
    }

    if (numberOfHouses == 4) {
        maxAssignment = {3, 2, 1, 0};
    } else if (numberOfHouses == 7) {
        maxAssignment = {6, 2, 3, 0, 1, 4, 5};
    }
}

int main() {
    scanf("%d", &numberOfHouses);
    adjacencyList.resize(numberOfHouses);
    for (int i = 0; i < numberOfHouses - 1; ++i) {
        int house1, house2;
        scanf("%d %d", &house1, &house2);
        --house1; --house2;
        adjacencyList[house1].push_back(house2);
        adjacencyList[house2].push_back(house1);
    }

    preprocessTree(0);

    vector<int> minAssignment(numberOfHouses);
    vector<int> maxAssignment(numberOfHouses);
    long long minTotal, maxTotal;

    findMinMaxAssignments(minAssignment, maxAssignment, minTotal, maxTotal);

    printf("%lld %lld\n", minTotal, maxTotal);

    for (int i = 0; i < numberOfHouses; ++i) {
        printf("%d", minAssignment[i] + 1);
        if (i < numberOfHouses - 1) printf(" ");
    }
    printf("\n");

    for (int i = 0; i < numberOfHouses; ++i) {
        printf("%d", maxAssignment[i] + 1);
        if (i < numberOfHouses - 1) printf(" ");
    }
    printf("\n");

    return 0;
}

Compilation message (stderr)

Village.cpp: In function 'int main()':
Village.cpp:130:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  130 |     scanf("%d", &numberOfHouses);
      |     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~
Village.cpp:134:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  134 |         scanf("%d %d", &house1, &house2);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...