#include <compare>
#include <iostream>
#include <optional>
#include <print>
#include <ranges>
#include <set>
#include <vector>
 
class Edge {
public:
    int toIdx;
    int weight;
};
 
std::vector<std::optional<int>> shortestPaths(std::vector<std::vector<Edge>> const& graph, int startIdx) {
    class DijkstraState {
    public:
        int idx;
        int distance;
    };
 
    auto compareState = [](auto const& state1, auto const& state2) -> bool {
        if (auto cmp = state1.distance <=> state2.distance; std::is_neq(cmp)) {
            return std::is_lt(cmp);
        }
        if (auto cmp = state1.idx <=> state2.idx; std::is_neq(cmp)) {
            return std::is_lt(cmp);
        }
        return 0;
    };
 
    std::vector<std::optional<int>> distances(graph.size(), std::nullopt);
    distances[startIdx] = 0;
 
    std::set<DijkstraState, decltype(compareState)> states {{startIdx, 0}};
    
    while (!states.empty()) {
        auto curState = *states.begin();
        states.erase(states.begin());
 
        for (auto const& outEdge: graph[curState.idx]) {
            auto& currentBestDistance = distances[outEdge.toIdx];
            int potentialDistance = curState.distance + outEdge.weight;
 
            if (!currentBestDistance) {
                states.emplace(outEdge.toIdx, potentialDistance);
                currentBestDistance = potentialDistance;
            }
            else if (*currentBestDistance > potentialDistance) {
                auto nodeHandle = states.extract({outEdge.toIdx, *currentBestDistance});
                currentBestDistance = potentialDistance;
                nodeHandle.value().distance = potentialDistance;
                states.insert(std::move(nodeHandle)).position;
            }
        }
    }
 
    return distances;
}
 
int main() {
    auto graph = std::vector<std::vector<Edge>> {
        {{3, 3}},
        {{0, 5}, {2, 1}},
        {{0, 2}, {3, 10}},
        {},
        {}
    };
 
    auto distances = shortestPaths(graph, 1);
    for (auto const& [idx, distance]: distances | std::views::enumerate) {
        std::println("{}'s distance is {}", idx, distance ? *distance : -1);
    }
}