Problem:
Single Source Shortest Path
For a given weighted graph
G(V, E)
and a source
r
, find the source shortest path to each vertex from the source (SSSP: Single Source Shortest Path).
Input
An edge-weighted graph
G
(
V
,
E
) and the source
r
.
|
V
| |
E
|
r
s
0
t
0
d
0
s
1
t
1
d
1
:
s
|E|-1
t
|E|-1
d
|E|-1
|V|
is the number of vertices and
|E|
is the number of edges in
G
. The graph vertices are named with the numbers 0, 1,...,
|V|-1
respectively.
r
is the source of the graph.
s
i
and
t
i
represent source and target vertices of
i
-th edge (directed) and
d
i
represents the cost of the
i
-th edge.
Output
Print the costs of SSSP in the following format.
c
0
c
1
:
c
|V|-1
The output consists of
|V|
lines. Print the cost of the shortest path from the source
r
to each vertex 0, 1, ...
|V|-1
in order. If there is no path from the source to a vertex, print
INF
.
Constraints
1 ≤
|V|
≤ 100000
0 ≤
d
i
≤ 10000
0 ≤
|E|
≤ 500000
There are no parallel edges
There are no self-loops
Sample Input 1
4 5 0
0 1 1
0 2 4
1 2 2
2 3 1
1 3 5
Sample Output 1
0
1
3
4
Sample Input 2
4 6 1
0 1 1
0 2 4
2 0 1
1 2 2
3 1 1
3 2 5
Sample Output 2
3
0
2
INF

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=long long;
using P=pair<ll,int>;

int main(){
    int V, E, r;
    cin >> V >> E >> r;
    vector<vector<P>> G(V,vector<P>(0));
    for(int i=0; i<E; i++){
        int s, t;
        ll d;
        cin >> s >> t >> d;
        G[s].push_back({d,t});
    }

    ll INF=1e18;
    vector<ll> dist(V,INF);
    priority_queue<P, vector<P>, greater<P>> q;
    dist[r]=0;
    q.push({0,r});

    while(q.size()){
        auto [td,tv]=q.top();
        q.pop();
        if(td!=dist[tv]) continue;
        for( P p : G[tv]){
            ll nd=p.first;
            int nv=p.second;
            if(nd+dist[tv]>=dist[nv]) continue;
            dist[nv]=nd+dist[tv];
            q.push({dist[nv],nv});
        }
    }

    for(int i=0; i<V; i++){
        if(dist[i]==INF){
            cout << "INF" << endl;
        }
        else{
            cout << dist[i] << endl;
        }
    }
}
accuracy: 1
time_ms: 310
memory_kb: 19464
final_rank: 10

code_snippet: #include <iostream>
#include <vector>
#include <queue>

using namespace std;

struct Edge{
    int from;
    int to;
    int d;
};

struct Node{
    int index;
    int cost;
};

int main(){
    int V, E, start;
    cin >> V >> E >> start;
    vector<vector<Edge>> G(V);
    for (int i=0; i<E; i++){
        int s,t,d;
        Edge e;
        cin >> s >> t >> d;
        e.from = s;
        e.to = t;
        e.d = d;
        G[s].push_back(e);
    }

    int INF = 1<<30;
    auto comp = [] (Node a, Node b){
        return a.cost > b.cost;
    };
    priority_queue<Node, vector<Node>, decltype(comp)> q{comp};
    q.push(Node{start, 0});
    vector<int> minCost(V, INF);
    minCost[start] = 0;

    while(!q.empty()){
        Node n = q.top();
        int now = n.index;
        int cost = n.cost;
        q.pop();
        // 既に最短経路が見つかっている場合
        if (cost > minCost[now]) continue;
        for (Edge e: G[now]){
            int newCost = cost + e.d;
            // より短い経路を見つけられなかった場合
            if (newCost > minCost[e.to]) continue;
            // 暫定の最短経路を更新し、さらに探索。
            minCost[e.to] = newCost;
            q.push(Node{e.to, newCost});
        }
    }

    for (int i=0; i<V; i++){
        if (minCost[i] == INF) cout << "INF" << endl;
        else cout << minCost[i] << endl;
    }


    return 0;
}
accuracy: 1
time_ms: 300
memory_kb: 15420
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <queue>

using namespace std;

int main(){
    long long int V, E, r;
    cin >> V >> E >> r;
    vector<vector<pair<int,int>>> G(V);
    for (int i=0; i<E; i++){
        int s, t, d;
        cin >> s >> t >> d;
        G[s].push_back({t,d});
        // G[t].push_back({s,d});
    }
    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> q;
    q.push({0,r});
    long long int INF = 1<<30;
    vector<long long int> distance(V, INF);
    distance[r] = 0;

    while(!q.empty()){
        auto top = q.top();
        q.pop();
        int d = top.first;
        int now = top.second;
        if (d > distance[now]) continue;
        for(auto next: G[now]){
            int nextIndex = next.first;   
            int nextDistance = next.second;   
            int nextAllDistance = d + nextDistance;
            if (nextAllDistance > distance[nextIndex]) continue;
            distance[nextIndex] = nextAllDistance;
            q.push({nextAllDistance, nextIndex});
        }
    }

    for (int i=0; i<V; i++){
        if (distance[i] == INF) cout << "INF" << endl;
        else cout << distance[i] << endl;
    }
    
    return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 13540
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;
using pl = pair<ll, ll>;

#define rep(i, x) for (int i = 0; i < (x); ++i)
#define reps(i, pr, x) for (int i = (pr); i <= (x); ++i)
#define vl vector<ll>
#define fore(i, m2) for (auto &i : m2)
#define all(X) (X).begin(), (X).end()
#define out(X) std::cout << (X) << endl

template <class T> inline bool chmax(T &x, T y) {
    if (x < y) {
        x = y;
        return true;
    }
    return false;
}
template <class T> inline bool chmin(T &x, T y) {
    if (x > y) {
        x = y;
        return true;
    }
    return false;
}

const ll INF = (1LL << 62);
const ll MAX = (1e5 + 5);
const ll MOD = (1e9 + 7);

ll n, m;
vl dsts;
vector<vector<pl>> G;

void Dijkstra(ll st) {

    priority_queue<pl, vector<pl>, greater<pl>> q;
    q.emplace((dsts[st] = 0), st);

    while (!q.empty()) {
        const ll dst = q.top().first;
        const int from = q.top().second;
        q.pop();

        if (dsts[from] < dst) {
            continue;
        }

        for (const pl &nd : G[from]) {
            ll cost = nd.second, to = nd.first;
            const long long d = (dsts[from] + cost);

            if (d < dsts[to]) {
                q.emplace((dsts[to] = d), to);
            }
        }
    }
}

int main() {

    ll s;
    cin >> n >> m >> s;

    dsts.assign(n, INF);
    G.assign(n, vector<pl>());

    ll a, b, c;
    rep(i, m) {
        cin >> a >> b >> c;

        G[a].push_back({b, c});
    }

    Dijkstra(s);

    rep(i, n) {
        if (dsts[i] == INF) out("INF");
        else out(dsts[i]);
    }
}
accuracy: 1
time_ms: 310
memory_kb: 19620
final_rank: 11

code_snippet: #include <bits/stdc++.h>

using namespace std;
// #include "all.h"

#define int long long
#define uint unsigned int
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define is2pow(n) (n && (!(n & (n - 1))))
#define OPTIMIZE                                                                                                       \
    ios_base::sync_with_stdio(false);                                                                                  \
    cin.tie(nullptr);                                                                                                  \
    cout.tie(nullptr);

using ld = long double;
constexpr int maxn = 2e5;
constexpr int maxk = 305;
constexpr long long inf = 1e18;
constexpr ld eps = 1e-8L;
constexpr long long mod = 998244353;


using pii = pair<int,int>;
vector<vector<pii>> graph;
vector<int> dist;


void solve() {
    int n,m,s; cin >> n >> m >> s;
    graph.assign(n, vector<pii>());
    dist.assign(n,1e9);

    for (int i = 0; i < m; i++) {
        int u,v,w; cin >> u >> v >> w;
        graph[u].emplace_back(v,w);
    }
    set<pii> q;
    q.emplace(0,s);
    dist[s] = 0;
    while (!q.empty()) {
        auto [d, u] = *q.begin();
        q.erase(q.begin());
        if (dist[u] != d) continue;
        for (auto& edge : graph[u]) {
            if (dist[edge.first] > d + edge.second) {
                dist[edge.first] = d + edge.second;
                q.emplace(dist[edge.first], edge.first);
            }
        }
    }
    for (auto d : dist) {
        if (d!=1e9) cout << d << "\n";
        else cout << "INF\n";
    }


}

#define TES
#define LOCA
#define FIL

int32_t main() {
    OPTIMIZE;

#ifdef FILE
    freopen("coins.in", "r", stdin);
    freopen("coins.out", "w", stdout);
#endif
#ifdef LOCAL
    freopen("/home/sq/CLionProjects/graph/input.txt", "r", stdin);
#endif
    int tt = 1;
#ifdef TEST
    cin >> tt;
#endif
    while (tt--) {
        solve();
    }
}
accuracy: 1
time_ms: 120
memory_kb: 21680
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#pragma GCC target("avx2")
#ifndef LOCAL
#pragma GCC optimize("O3")
#endif
#pragma GCC optimize("unroll-loops")

#ifdef ONLINE_JUDGE
#include <boost/multiprecision/cpp_int.hpp>
#include <atcoder/all>
#endif
#ifdef LOCAL
#define GLIBCXX_DEBUG
#define endl endl<<flush
#else
#define endl "\n"
#endif
using namespace std;using ll=long long;using ull=unsigned long long;using dl=long double;
#define rep(i,n) for(ll i=0; i<(n); i++)
#define rrep(i,n) for(ll i=1; i<=(n); i++)
#define drep(i,n) for(ll i=(n)-1; i>=0; i--)
#define xfor(i,s,e) for(ll i=(s); i<(e); i++)
#define rxfor(i,s,e) for(ll i=(s); i<=(e); i++)
#define dfor(i,s,e) for(ll i=(s)-1; i>=(e); i--)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define chmax(x,y) x = max(x,y)
#define chmin(x,y) x = min(x,y)
#define popcnt(s) ll(__popcount<ull>(uint64_t(s)))
template<typename T>istream&operator>>(istream&is,pair<T,T>&v){is>>v.first>>v.second;return is;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(auto&in:v)is>>in;return is;}
template<typename T, typename U>ostream&operator<<(ostream&os,pair<T,U>&v){os<<v.first<<" "<<v.second;return os;}
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){for(auto&in:v)os<<in<<' ';return os;}
ll modpow(ll a, ll b, ll mod) {ll res = 1;while (b > 0) {if (b & 1) res = (res * a) % mod;a = (a * a) % mod;b >>= 1;}return res;}
ll powl(ll a, ll b) {ll res = 1;while (b > 0) {if (b & 1) res = (res * a);a = (a * a);b >>= 1;}return res;}
#define pow2(a) (a)*(a)
/*MOD MUST BE A PRIME NUMBER!!*/ll moddiv(const ll a, const ll b, const ll mod) {ll modinv = modpow(b, mod-2, mod);return (a * modinv) % mod;}
constexpr ll INF = 2e15;
ll nC2(const ll i){return i>2?i*(i-1)/2:0;}ll nC3(const ll i){return i>3?i*(i-1)*(i-2)/6:0;}ll nC4(const ll i){return i>4?i*(i-1)*(i-2)*(i-3)/24:0;}ll nC5(const ll i){return i>5?i*(i-1)*(i-2)*(i-3)*(i-4)/120:0;}ll nC6(const ll i){return i>6?i*(i-1)*(i-2)*(i-3)*(i-4)*(i-5)/720:0;}
void warshall_floyd(vector<vector<ll>>& dist) {const ull n = dist.size();rep(k, n) rep(i, n) rep(j, n) {dist[i][j] = min(dist[i][j],dist[i][k] + dist[k][j]);}}
#define YES {cout<<"Yes\n";return;}
#define NO {cout<<"No\n";return;}
#define yn YES else NO
#ifdef ONLINE_JUDGE
using lll = boost::multiprecision::cpp_int;
//using lll = boost::multiprecision::int128_t;
using namespace atcoder;
//using mint = modint1000000007;
using mint = modint998244353;
//using mint = modint; // custom mod
//atcoder::modint::set_mod(m);
// DSU == UnionFind
#endif
#define vc vector
using P = pair<ll, ll>;using vl = vc<ll>;using vb=vc<bool>;using vs=vc<string>;using vvl=vc<vl>;using vp=vc<P>;
#define pq priority_queue
template<typename T>void cs(vector<T>&v){xfor(i,1,v.size())v[i]+=v[i-1];}

vl dx = {-1, 1, 0, 0, -1, 1, -1, 1};
vl dy = {0, 0, 1, -1, -1, -1, 1, 1};

constexpr ll mod = 998244353;

void solve() {
    ll V, E, r;
    cin >> V >> E >> r;
    vc<vc<P>> nexts(V);
    rep(i, E) {
        ll s,t,d;
        cin>>s>>t>>d;
        nexts[s].emplace_back(t,d);
    }

    vl dijkstra(V, INF);
    dijkstra[r] = 0;

    pq<P, vector<P>, greater<>> q; // make_pair( 重みの総和, 頂点番号 )
    q.emplace(0, r);

    while (!q.empty()) {
        auto [_, vert] = q.top(); q.pop();

        for (auto [next, weight] : nexts[vert]) {
            if (dijkstra[next] > dijkstra[vert] + weight) {
                dijkstra[next] = dijkstra[vert] + weight;
                q.emplace(dijkstra[next], next);
            }
        }
    }

    rep(i,V)cout<<(dijkstra[i]==INF?"INF":to_string(dijkstra[i]))<<endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cout << fixed << setprecision(50);

    ll n = 1;
    //cin >> n;
    while (n--) {
        solve();
    }
}
accuracy: 1
time_ms: 110
memory_kb: 19536
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin >> n;
    int m;
    cin >> m;
    int k;
    cin >> k;
    k++;
    vector<vector<pair<int,int>>> adj(n+1);
    for(int i=0;i<m;i++){
        int a,b,w;
        cin >> a >> b >> w;
        a++; b++;
        adj[a].push_back({b,w});
    }
            priority_queue<pair<int,int>> q;
        vector<int> d(n+1, INT_MAX);
        q.push({0,k});
        d[k]=0;
        while(!q.empty()){
            int a=q.top().first, b=q.top().second;
            q.pop();
            if(d[b]!=INT_MAX && b!=k) continue;
            d[b]=-a;
            for(auto nxt:adj[b]){
                if(d[nxt.first]==INT_MAX) q.push({-(-a+nxt.second),nxt.first});
            }
        }
        for(int i=1;i<=n;i++){
            if(d[i]!=INT_MAX) cout << d[i] << '\n';
            else cout << "INF\n";
        }
}
accuracy: 1
time_ms: 260
memory_kb: 14160
final_rank: 2

code_snippet: #include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <iomanip>
#include <numeric>
#include <queue>
#include <stack>
using namespace std;
using ll = long long;
struct Edge {
	int to;
	int cost;
};
using Graph = vector<vector<Edge>>;
int main() {
	int N, M, r;cin >> N >> M >>r;
	Graph G(N);
	for (int i = 0;i < M;i++) {
		int a, b, c;cin >> a >> b >> c;
		G[a].push_back({b, c});
	}
	ll inf = (1LL << 60);
	vector<ll> dist(N, inf);
	priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;
	dist[r] = 0;
	pq.push({0, r});
	while (!pq.empty()) {
		auto tp = pq.top();
		pq.pop();
		int v = tp.second;
		ll d = tp.first;
		if (dist[v] < d) continue;
		for (auto nv : G[v]) {
			if (nv.cost+d < dist[nv.to]) {
				dist[nv.to] = d + nv.cost;
				pq.push({dist[nv.to], nv.to});
			}
		}
	}
	for (int v = 0;v < N;v++) {
		if (dist[v] == inf) {
			cout << "INF" << endl;
		} else {
			cout << dist[v] << endl;
		}
	}
}
accuracy: 1
time_ms: 310
memory_kb: 14492
final_rank: 6

code_snippet: #line 1 "src/main.cpp"
#include <bits/stdc++.h>

#line 2 "library/newlib/src/Functional.hpp"
#include <type_traits>
#line 5 "library/newlib/src/Functional.hpp"

namespace gandalfr {

namespace internal {
template <typename T>
bool chmin(T &a, const T &b) {
    return b < a ? (a = b, true) : false;
}
template <typename T>
bool chmax(T &a, const T &b) {
    return a < b ? (a = b, true) : false;
}
}  // namespace internal

namespace mixin {
struct HasFrom {
    int _from;
    HasFrom() = default;
    HasFrom(int from) : _from(from) {}
    int from() const { return _from; }
};
struct HasTo {
    int _to;
    HasTo() = default;
    HasTo(int to) : _to(to) {}
    int to() const { return _to; }
};
struct HasOther {
    int _xor;
    HasOther() = default;
    HasOther(int xor_val) : _xor(xor_val) {}
    int other(int from) const { return from ^ _xor; }
};
template <typename WeightType>
struct WithCost {
    using W = WeightType;
    WeightType _cost;
    WithCost() = default;
    WithCost(WeightType cost) : _cost(cost) {}
    WeightType cost() const { return _cost; }
};
template <typename WeightType = int>
struct HasConstCost {
    using W = WeightType;
    HasConstCost() = default;
    HasConstCost(WeightType) {}  // dummy
    WeightType cost() const { return 1; }
};
template <typename InfoType>
struct WithInfo {
    InfoType _info;
    WithInfo() = default;
    WithInfo(InfoType info) : _info(info) {}
    InfoType info() const { return _info; }
};
}  // namespace mixin

namespace detail {
template <typename T>
struct cost_type_of {
    using type = void;
};
template <typename WeightType>
struct cost_type_of<mixin::WithCost<WeightType>> {
    using type = WeightType;
};
template <typename WeightType>
struct cost_type_of<mixin::HasConstCost<WeightType>> {
    using type = WeightType;
};

template <typename... Ts>
struct find_cost_type_helper;
template <>
struct find_cost_type_helper<> {
    using type = void;
};
template <typename Head, typename... Tail>
struct find_cost_type_helper<Head, Tail...>
    : std::conditional_t<
          !std::is_same_v<typename cost_type_of<Head>::type, void>,
          cost_type_of<Head>, find_cost_type_helper<Tail...>> {};
}  // namespace detail

template <typename... OptionalProperties>
struct Edge : public OptionalProperties... {
    using W =
        typename detail::find_cost_type_helper<OptionalProperties...>::type;

    Edge() = default;
    Edge(const Edge &) = default;
    Edge(Edge &&) = default;
    Edge &operator=(const Edge &) = default;
    Edge &operator=(Edge &&) = default;

    template <typename... Args>
    Edge(Args &&...args) : OptionalProperties(std::forward<Args>(args))... {}
};
namespace edge {
using UnweightedEdge = Edge<mixin::HasOther, mixin::HasConstCost<>>;
template <typename InfoType>
using UnweightedEdgeWithInfo =
    Edge<mixin::HasOther, mixin::HasConstCost<>, mixin::WithInfo<InfoType>>;
template <typename WeightType>
using WeightedEdge = Edge<mixin::HasOther, mixin::WithCost<WeightType>>;
template <typename WeightType, typename InfoType>
using WeightedEdgeWithInfo = Edge<mixin::HasOther, mixin::WithCost<WeightType>,
                                  mixin::WithInfo<InfoType>>;
}  // namespace edge

template <typename E, bool is_directed>
struct General {
    using W = typename E::W;
    static_assert(std::is_base_of_v<mixin::HasOther, E>,
                  "E must have to(int) method");
    static_assert(std::is_base_of_v<mixin::HasConstCost<W>, E> ^
                      std::is_base_of_v<mixin::WithCost<W>, E>,
                  "E must have either HasConstCost or WithCost mixin");

    int _n = 0;
    std::vector<int> _idx, _ptr;
    std::vector<E> _edges;

    template <typename Iterator>
    class IndexRange {
       private:
        Iterator _begin_it;
        Iterator _end_it;

       public:
        IndexRange(Iterator begin_it, Iterator end_it)
            : _begin_it(begin_it), _end_it(end_it) {}
        Iterator begin() const { return _begin_it; }
        Iterator end() const { return _end_it; }
    };
    IndexRange<typename std::vector<int>::const_iterator> operator[](
        int v) const {
        auto begin_it = _idx.cbegin() + _ptr[v];
        auto end_it = _idx.cbegin() + _ptr[v + 1];
        return {begin_it, end_it};
    }

    General(int n) : _n(n) {}

    void build(const std::vector<int> &from_v, const std::vector<E> &e_v) {
        assert(from_v.size() == e_v.size());
        int m = e_v.size();
        _edges = e_v;
        _ptr.assign(_n + 1, 0);
        for (int i = 0; i < m; i++) {
            int from = from_v[i];
            int to = e_v[i].other(from);
            _ptr[from + 1]++;
            if (!is_directed && from != to) _ptr[to + 1]++;
        }
        for (int v = 0; v < _n; v++) _ptr[v + 1] += _ptr[v];

        int idx_size = is_directed ? m : 2 * m;
        _idx.assign(idx_size, -1);
        std::vector<int> counter = _ptr;
        for (int i = 0; i < m; i++) {
            int from = from_v[i];
            int to = e_v[i].other(from);
            int dest_idx = counter[from]++;
            _idx[dest_idx] = i;
            if (!is_directed && from != to) {
                int rev_dest_idx = counter[to]++;
                _idx[rev_dest_idx] = i;
            }
        }
    }

    int vertex_count() const { return _n; }
    int edge_count() const { return (int)_edges.size(); }

    const E &edge_at(int i) const { return _edges[i]; }
    E &edge_at(int i) { return _edges[i]; }

    template <bool D = std::is_base_of_v<mixin::WithCost<W>, E>>
    auto dijkstra(int s) -> std::enable_if_t<D, std::vector<W>> {
        const W INF = std::numeric_limits<W>::max();
        std::vector<W> dist(_n, INF);
        using P = std::pair<W, int>;
        std::priority_queue<P, std::vector<P>, std::greater<P>> pq;
        dist[s] = W(0);
        pq.push({dist[s], s});
        while (!pq.empty()) {
            auto [d, v] = pq.top();
            pq.pop();
            if (dist[v] < d) continue;
            for (int ei : (*this)[v]) {
                const E &e = edge_at(ei);
                int to = e.other(v);
                W nd = d + e.cost();
                if (internal::chmin(dist[to], nd)) pq.push({nd, to});
            }
        }
        return dist;
    }

    template <bool D = std::is_base_of_v<mixin::HasConstCost<W>, E>>
    auto bfs(int s) -> std::enable_if_t<D, std::vector<W>> {
        std::vector<W> dist(_n, W(std::numeric_limits<W>::max()));
        std::queue<int> q;
        dist[s] = W(0);
        q.push(s);
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            for (int ei : (*this)[v]) {
                const E &e = edge_at(ei);
                int to = e.other(v);
                W nd = dist[v] + e.cost();
                if (internal::chmin(dist[to], nd)) q.push(to);
            }
        }
        return dist;
    }
};

}  // namespace gandalfr
#line 4 "src/main.cpp"

using namespace std;
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define rep(i, n) for (int i = 0; i < (n); i++)
#define all(a) (a).begin(), (a).end()
using ll = long long;

using namespace gandalfr;

int main() {
    int n, m, s;
    cin >> n >> m >> s;
    General<edge::WeightedEdge<int>, true> graph(n);
    vector<int> froms;
    vector<edge::WeightedEdge<int>> edges;
    for (int i = 0; i < m; i++) {
        int from, to, cost;
        cin >> from >> to >> cost;
        edges.push_back({from ^ to, cost});
        froms.push_back(from);
    }
    graph.build(froms, edges);

    auto dist = graph.dijkstra(s);
    for (int v = 0; v < graph.vertex_count(); v++) {
        if (dist[v] == std::numeric_limits<int>::max()) {
            cout << "INF" << endl;
            continue;
        }
        cout << dist[v] << endl;
    }
}
accuracy: 1
time_ms: 290
memory_kb: 17240
final_rank: 8

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#include <iostream>
#include<vector>
#include<list>
#include<utility>
#include<limits>
#include<set>
#include<iostream>
#include<queue>
#include<unordered_map>
#include<unordered_set>
#include<random>
#include<ext/pb_ds/assoc_container.hpp>

using T = long long;
namespace spp {

using namespace std;
using namespace __gnu_pbds;

template<typename K, typename V>
using hash_map = unordered_map<K, V>;
template<typename K>
using hash_set = unordered_set<K>;

template<typename uniqueDistT>
struct batchPQ { // batch priority queue, implemented as in Lemma 3.3
    using elementT = pair<int,uniqueDistT>;
    
    struct CompareUB {
        template <typename It>
        bool operator()(const pair<uniqueDistT, It>& a, const pair<uniqueDistT, It>& b) const {
            if (a.first != b.first) return a.first < b.first;
            return  addressof(*a.second) < addressof(*b.second);
        }
    };
    
    typename list<list<elementT>>::iterator it_min;
    
    list<list<elementT>> D0,D1;
    set<pair<uniqueDistT,typename list<list<elementT>>::iterator>,CompareUB> UBs; // (UB, it_block)
    
    int M,size_;
    uniqueDistT B;
    
    hash_map<int, uniqueDistT> actual_value;
    hash_map<int, pair< typename list<list<elementT>>::iterator , typename list<elementT>::iterator> > where_is[2];
    
    // Initialize
    batchPQ(int M_, uniqueDistT B_): M(M_), B(B_) { // O(1)
        D1.push_back(list<elementT>());
        UBs.insert({B_,D1.begin()});
        size_ = 0;
    }
    
    int size(){
        return size_;
    }
    
    inline void erase(int key) {
        if(actual_value.find(key) != actual_value.end())
            delete_({-1, -1, key, -1});
    }
    void delete_(uniqueDistT x){    
        int a = get<2>(x);
        uniqueDistT b = actual_value[a];
        
        auto it_w = where_is[1].find(a);
        if((it_w != where_is[1].end())){
            auto [it_block,it] = it_w->second;
            
            (*it_block).erase(it);
            where_is[1].erase(a);
    
            if((*it_block).size() == 0){
                auto it_UB_block = UBs.lower_bound({b,it_block});  
                
                if((*it_UB_block).first != B){
                    UBs.erase(it_UB_block);
                    D1.erase(it_block);
                }
            }
        }else{
            auto [it_block,it] = where_is[0][a];
            (*it_block).erase(it);
            where_is[0].erase(a);
            if((*it_block).size() == 0) D0.erase(it_block); 
        }
    
        actual_value.erase(a);
        size_--;
    }
    
    void insert(uniqueDistT x){ // O(lg(Block Numbers))         
        uniqueDistT b = x;
        int a = get<2>(b);
    
        // checking if exists
        auto it_exist = actual_value.find(a);
        int exist = (it_exist != actual_value.end()); 
    
        if(exist && it_exist->second > b){
            delete_(x);
        }else if(exist){
            return;
        }
        
        // Searching for the first block with UB which is > 
        auto it_UB_block = UBs.lower_bound({b,it_min});
        auto [ub,it_block] = (*it_UB_block);
                
        // Inserting key/value (a,b)
        auto it = it_block->insert(it_block->end(),{a,b});
        where_is[1][a] = {it_block, it};
        actual_value[a] = b;
    
        size_++;
    
        // Checking if exceeds the sixe limit M
        if((*it_block).size() > M){
            split(it_block);
        }
    }

    uniqueDistT medianOfMedians(vector<elementT>::iterator bg, vector<elementT>::iterator en) {
        vector<elementT> l(bg, en);
        while (true) {
            int n = l.size();

            if (n <= 5) {
                sort(l.begin(), l.end(), [](const auto& a, const auto& b) {
                    return a.second < b.second;
                });
                return l[l.size() / 2].second;
            }

            vector<elementT> medians;
            medians.reserve((n + 4) / 5);

            auto it = l.begin();
            while (it != l.end()) {
                vector<elementT> group;
                group.reserve(5);
                for (int j = 0; j < 5 && it != l.end(); ++j, ++it)
                    group.push_back(*it);

                sort(group.begin(), group.end(), [](const auto& a, const auto& b) {
                    return a.second < b.second;
                });

                medians.push_back(group[group.size() / 2]);
            }

            l = move(medians);
        }
    }
    
    uniqueDistT selectKth(vector<elementT> &v, int k) { 
        using std::swap;
        int l=0, r=v.size()-1;
        
        for(;l<=r;){
            uniqueDistT p = medianOfMedians(v.begin() + l, v.begin() + r + 1);
            
            int i = l, j = r, m = l;
            
            while(m <= j){
                if(v[m].second < p) {
                    swap(v[m++],v[i++]);
                }else if(v[m].second > p){
                    swap(v[m],v[j--]);
                }else{
                    m++;
                }
            }
        
            if (k < i) r = i - 1;     // k está na parte menor
            else if (k > j) l = j + 1;     // k está na parte maior
            else return v[k].second; // k está entre os iguais ao pivot
        } 
        
        return v[k].second;
    }

        
    void split(list<list<elementT>>::iterator it_block){ // O(M) + O(lg(Block Numbers))
        int sz = (*it_block).size();
        
        vector<elementT> v((*it_block).begin() , (*it_block).end());
        uniqueDistT med = selectKth(v,(sz/2)); // O(M)
        
        auto pos = it_block;
        pos++;


        auto new_block = D1.insert(pos,list<elementT>());
        auto it = (*it_block).begin();
    
        while(it != (*it_block).end()){ // O(M)
            if((*it).second >= med){
                // (*new_block).push_back((*it));
                (*new_block).push_back(move(*it));
                auto it_new = (*new_block).end(); it_new--;
                where_is[1][(*it).first] = {new_block, it_new};
    
                it = (*it_block).erase(it);
            }else{
                it++;
            }
        }
    

        // Updating UBs   
        // O(lg(Block Numbers))
        uniqueDistT UB1 = {get<0>(med),get<1>(med),get<2>(med),get<3>(med)-1};
        auto it_lb = UBs.lower_bound({UB1,it_min});
        auto [UB2,aux] = (*it_lb);
        
        UBs.insert({UB1,it_block});
        UBs.insert({UB2,new_block});
        
        UBs.erase(it_lb);
    }
    
    void batchPrepend(const list<elementT> &l) { // O(|l| log(|l|/M) ) 
        int sz = l.size();
        
        if(sz == 0) return;
        if(sz <= M){
    
            D0.push_front(list<elementT>());
            auto new_block = D0.begin();
            
            for(auto &x : l){ 
                auto it = actual_value.find(x.first);
                int exist = (it != actual_value.end()); 
    
                if(exist && it->second > x.second){
                    delete_(x.second);
                }else if(exist){
                    continue;
                }
    
                (*new_block).push_back(x);
                auto it_new = (*new_block).end(); it_new--;
                where_is[0][x.first] = {new_block, it_new};
                actual_value[x.first] = x.second;
                size_++;
            }
            if(new_block->size() == 0) D0.erase(new_block);
            return;
        }

        vector<elementT> v(l.begin(), l.end());
        uniqueDistT med = selectKth(v, sz/2);
    
        list<elementT> less,great;
        for(auto [a,b]: l){
            if(b < med){
                less.push_back({a,b});
            }else if(b > med){
                great.push_back({a,b});
            }
        }
        
        great.push_back({get<2>(med),med});

        batchPrepend(great);
        batchPrepend(less);
    }
    
    void batchPrepend(const vector<uniqueDistT> &v){
        list<elementT> l;
        for(auto x: v){
            l.push_back({get<2>(x),x});
        }
        batchPrepend(l);
    }
    
    pair<uniqueDistT, vector<int>> pull(){ // O(M)
        vector<elementT> s0,s1;
        s0.reserve(2 * M); s1.reserve(M);
    
        auto it_block = D0.begin();
        while(it_block != D0.end() && s0.size() <= M){ // O(M)   
            for (const auto& x : *it_block) s0.push_back(x);
            it_block++;
        }
    
        it_block = D1.begin();
        while(it_block != D1.end() && s1.size() <= M){   //O(M)
            for (const auto& x : *it_block) s1.push_back(x);
            it_block++;
        }
    
        if(s1.size() + s0.size() <= M){
            vector<int> ret;
            ret.reserve(s1.size()+s0.size());
            for(auto [a,b] : s0) {
                ret.push_back(a);
                delete_({b});
            }
            for(auto [a,b] : s1){
                ret.push_back(a);
                delete_({b});
            } 
    
            return {B, ret};
        }else{  
            vector<elementT> &l = s0;
            l.insert(l.end(), s1.begin(), s1.end());

            uniqueDistT med = selectKth(l, M);
            vector<int> ret;
            ret.reserve(M);
            for(auto [a,b]: l){
                if(b < med) {
                    ret.push_back(a);
                    delete_({b});
                }
            }
            
            return {med,ret};
        }
    }
};

template<typename wT>
struct bmssp { // bmssp class
    int n, k, t;
    const wT oo = numeric_limits<wT>::max() / 10;
 
    vector<vector<pair<int, wT>>> ori_adj;
    vector<vector<pair<int, wT>>> adj;
    vector<wT> d;
    vector<int> pred, path_sz;
    vector<int> rev_map;
    vector<short int> last_complete_lvl;
 
    vector<hash_map<int, int>> neig;
    bmssp(int n_): n(n_) {
        ori_adj.assign(n, {});
        neig.assign(n, {});
    }
    bmssp(const auto &adj) {
        n = adj.size();
        ori_adj = adj;
        neig.assign(n, {});
    }
    void addEdge(int a, int b, wT w) {
        ori_adj[a].emplace_back(b, w);
    }

    // if the graph already has constant degree, prepage_graph(false)
    // else, prepage_graph(true)
    void prepare_graph(bool exec_constant_degree_trasnformation = false) {
        // erase duplicated edges
        vector<pair<int, int>> tmp_edges(n, {-1, -1});
        for(int i = 0; i < n; i++) {
            vector<pair<int, wT>> nw_adj;
            nw_adj.reserve(ori_adj[i].size());
            for(auto [j, w]: ori_adj[i]) {
                if(tmp_edges[j].first != i) {
                    nw_adj.emplace_back(j, w);
                    tmp_edges[j] = {i, nw_adj.size() - 1};
                } else {
                    int id = tmp_edges[j].second;
                    nw_adj[id].second = min(nw_adj[id].second, w);
                }
            }
            ori_adj[i] = move(nw_adj);
        }
        tmp_edges.clear();

        if(exec_constant_degree_trasnformation == false) {
            adj = move(ori_adj);
            ori_adj.clear();
            d.resize(n);
            root.resize(n);
            pred.resize(n);
            treesz.resize(n);
            rev_map.resize(n);
            path_sz.resize(n, 0);
            last_complete_lvl.resize(n);
            
            for(int i = 0; i < n; i++) {
                neig[i][i] = i;
                rev_map[i] = i;
            }

            k = floor(pow(log2(n), 1.0 / 3.0));
            t = floor(pow(log2(n), 2.0 / 3.0));
        } else {
            // Make the graph become constant degree
            int cnt = 0;
            for(int i = 0; i < n; i++) {
                for(auto [j, w]: ori_adj[i]) {
                    if(neig[i].find(j) == neig[i].end()) {
                        neig[i][j] = cnt++;
                        neig[j][i] = cnt++;
                    }
                }
            }

            cnt++;
            adj.assign(cnt, {});
            
            d.resize(cnt);
            root.resize(cnt);
            pred.resize(cnt);
            treesz.resize(cnt);
            rev_map.resize(cnt);
            path_sz.resize(cnt, 0);
            last_complete_lvl.resize(cnt);
    
            for(int i = 0; i < n; i++) { // create 0-weight cycles
                for(auto cur = neig[i].begin(); cur != neig[i].end(); cur++) {
                    auto nxt = next(cur);
                    if(nxt == neig[i].end()) nxt = neig[i].begin();
                    adj[cur->second].emplace_back(nxt->second, wT());
                    rev_map[cur->second] = i;
                }
            }
            for(int i = 0; i < n; i++) { // add edges
                for(auto [j, w]: ori_adj[i]) {
                    adj[neig[i][j]].emplace_back(neig[j][i], w);
                }
                if(neig[i].size() == 0) { // for vertices without edges
                    neig[i][n] = cnt - 1;
                }
            }
            k = floor(pow(log2(cnt), 1.0 / 3.0));
            t = floor(pow(log2(cnt), 2.0 / 3.0));
            
            ori_adj.clear();
        }
    }
    
    int toAnyCustomNode(int real_id) {
        return neig[real_id].begin()->second;
    }
    int customToReal(int id) {
        return rev_map[id];
    }
 
    vector<wT> execute(int s) {
        fill(d.begin(), d.end(), oo);
        fill(path_sz.begin(), path_sz.end(), oo);
        fill(last_complete_lvl.begin(), last_complete_lvl.end(), -1);
        for(int i = 0; i < pred.size(); i++) pred[i] = i;
        
        s = toAnyCustomNode(s);
        d[s] = 0;
        path_sz[s] = 0;
        
        const int l = ceil(log2(adj.size()) / t);
        const uniqueDistT inf_dist = make_tuple(oo, 0, 0, 0);
        bmsspRec(l, inf_dist, {s});
 
        vector<wT> res(n);
        for(int i = 0; i < n; i++) res[i] = d[toAnyCustomNode(i)];
        return res;
    }
    
    // ===================================================================
 
    // set stuff
    // template<typename T>
    // void removeDuplicates(vector<T> &v) { // sort is faster
    //     hash_set<T> s(v.begin(), v.end());
    //     v = vector<T>(s.begin(), s.end());
    //     // sort(v.begin(), v.end());
    //     // v.erase(unique(v.begin(), v.end()), v.end());
    // }
    template<typename T>
    bool isUnique(const vector<T> &v) {
        auto v2 = v;
        sort(v2.begin(), v2.end());
        v2.erase(unique(v2.begin(), v2.end()), v2.end());
        return v2.size() == v.size();
    }

    using uniqueDistT = tuple<wT, int, int, int>;
    inline uniqueDistT getDist(int u, int v, int w) {
        return {d[u] + w, path_sz[u] + 1, v, u};
    }
    inline uniqueDistT getDist(int u) {
        return {d[u], path_sz[u], u, pred[u]};
    }
    void updateDist(int u, int v, wT w) {
        pred[v] = u;
        d[v] = d[u] + w;
        path_sz[v] = path_sz[u] + 1;
    }
    // ===================================================================
    vector<int> root;
    vector<short int> treesz;
    pair<vector<int>, hash_set<int>> findPivots(uniqueDistT B, const vector<int> &S) { // Algorithm 1
        hash_set<int> vis;
        vis.reserve(S.size() * k);
        vis.insert(S.begin(), S.end());

        vector<int> active = S;
        for(int x: S) root[x] = x, treesz[x] = 0;
        for(int i = 1; i <= k; i++) {
            vector<int> nw_active;
            nw_active.reserve(active.size() * 4);
            for(int u: active) {
                for(auto [v, w]: adj[u]) {
                    if(getDist(u, v, w) <= getDist(v)) {
                        updateDist(u, v, w);
                        if(getDist(v) < B) {
                            root[v] = root[u];
                            nw_active.push_back(v);
                        }
                    }
                }
            }
            for(const auto &x: nw_active) {
                vis.insert(x);
            }
            if(vis.size() > k * S.size()) {
                return {S, vis};
            }
            active = move(nw_active);
        }

        vector<int> P;
        P.reserve(vis.size() / k);
        for(int u: vis) treesz[root[u]]++;
        for(int u: S) if(treesz[u] >= k) P.push_back(u);
        
        // assert(P.size() <= vis.size() / k);
        return {P, vis};
    }
 
    pair<uniqueDistT, vector<int>> baseCase(uniqueDistT B, int x) { // Algorithm 2
        vector<int> complete;
        complete.reserve(k + 1);
 
        priority_queue<uniqueDistT, vector<uniqueDistT>, greater<uniqueDistT>> heap;
        heap.push(getDist(x));
        while(heap.empty() == false && complete.size() < k + 1) {
            int u = get<2>(heap.top());
            int du = get<0>(heap.top());
            heap.pop();
            if(du > d[u]) continue;

            complete.push_back(u);
            for(auto [v, w]: adj[u]) {
                auto new_dist = getDist(u, v, w);
                auto old_dist = getDist(v);
                if(new_dist <= old_dist && new_dist < B) {
                    updateDist(u, v, w);
                    heap.push(new_dist);
                }
            }
        }
        if(complete.size() <= k) return {B, complete};
 
        uniqueDistT nB = getDist(complete.back());
        // {   // sanity check
        //     int cntbig = 0;
        //     for(int u: complete) if(getDist(u) >= nB) cntbig++;
        //     assert(cntbig == 1);
        //     for(int u: complete) assert(getDist(u) < B);
        //     assert(complete.size() == k + 1);
        // }
        complete.pop_back();
        return {nB, complete};
    }
 
    pair<uniqueDistT, vector<int>> bmsspRec(short int l, uniqueDistT B, const vector<int> &S) { // Algorithm 3
        if(l == 0) return baseCase(B, S[0]);
 
        auto [P, bellman_vis] = findPivots(B, S);
 
        const long long batch_size = (1ll << ((l - 1) * t));
        batchPQ<uniqueDistT> D(batch_size, B);
        for(int p: P) D.insert(getDist(p));
 
        uniqueDistT last_complete_B = B;
        for(int p: P) last_complete_B = min(last_complete_B, getDist(p));
 
        vector<int> complete;
        const long long quota = k * (1ll << (l * t));
        complete.reserve(quota + bellman_vis.size());
        while(complete.size() < quota && D.size()) {
            auto [trying_B, miniS] = D.pull();
            // all with dist < trying_B, can be reached by miniS <= req 2, alg 3
 
            auto [complete_B, nw_complete] = bmsspRec(l - 1, trying_B, miniS);
            
            // all new complete_B are greater than the old ones <= point 6, page 10
            // assert(last_complete_B < complete_B);
 
            complete.insert(complete.end(), nw_complete.begin(), nw_complete.end());
            // point 6, page 10 => complete does not intersect with nw_complete
            // assert(isUnique(complete));
 
            vector<uniqueDistT> can_prepend;
            can_prepend.reserve(nw_complete.size() * 5 + miniS.size());
            for(int u: nw_complete) {
                D.erase(u); // priority queue fix
                last_complete_lvl[u] = l;
                for(auto [v, w]: adj[u]) {
                    auto new_dist = getDist(u, v, w);
                    if(new_dist <= getDist(v)) {
                        updateDist(u, v, w);
                        if(trying_B <= new_dist && new_dist < B) {
                            D.insert(new_dist); // d[v] can be greater equal than min(D), occur 1x per vertex
                        } else if(complete_B <= new_dist && new_dist < trying_B) {
                            can_prepend.emplace_back(new_dist); // d[v] is less than all in D, can occur 1x at each level per vertex
                        }
                    }
                }
            }
            for(int x: miniS) {
                if(complete_B <= getDist(x)) can_prepend.emplace_back(getDist(x));
                // second condition is not necessary
            }
            // can_prepend is not necessarily all unique
            D.batchPrepend(can_prepend);
 
            last_complete_B = complete_B;
        }
        uniqueDistT retB;
        if(D.size() == 0) retB = B;     // successful
        else retB = last_complete_B;    // partial
 
        for(int x: bellman_vis) if(last_complete_lvl[x] != l && getDist(x) < retB) complete.push_back(x); // this get the completed vertices from bellman-ford, it has P in it as well
        // get only the ones not in complete already, for it to become disjoint
 
        return {retB, complete};
    }
};
}

int main() {
    int n, m, s;
    std::cin >> n >> m >> s;
    std::vector<std::tuple<int, int, T>> edges;
    while (m --)
    {
        int u, v, w;
        std::cin >> u >> v >> w;
        edges.push_back({u, v, w});
    }
    
    // std::vector<std::tuple<int, int, T>> edges = {
    //     {0, 1, 10}, {0, 2, 3}, {1, 3, 2}, {2, 1, 4},
    //     {2, 3, 8}, {2, 4, 2}, {3, 4, 5}
    // };
    int source_node = s;

    // 2. Initialize and build the graph
    spp::bmssp<T> solver(n);
    for (const auto& [u, v, weight] : edges) {
        solver.addEdge(u, v, weight);
    }

    // 3. Prepare the graph (must be called once)
    solver.prepare_graph(false);
    // use solver.prepare_graph(true) if the graph does not have contant out-degree

    // 4. Compute shortest paths
    std::vector<T> distances = solver.execute(source_node);

    // 5. Print results
    // std::cout << "Shortest paths from source " << source_node << ":" << std::endl;
    for (int i = 0; i < n; ++i) {
        if (distances[i] == solver.oo) {
            std::cout << "INF" << '\n';
        } else {
            std::cout << distances[i] << '\n';
        }
    }

    return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 56536
final_rank: 18

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#include <iostream>
#include <vector>
#include <cmath>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <limits>
#include <map>
#include <algorithm>
#include <cassert>

using Vertex = int;
using Length = long long;
const Length INF = std::numeric_limits<long long>::max();
using Edge = std::pair<Vertex, Length>;
using Graph = std::vector<std::vector<Edge>>;

class BlockHeap {
    public:
        BlockHeap(int M, Length B);
        void insert(Vertex v, Length l);
        void batch_prepend(const std::vector<std::pair<Vertex, Length>>& L);
        std::pair<Length ,std::vector<Vertex>> pull();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;


        std::unordered_map<Vertex, Length> d_;
        std::vector<std::pair<Length, Vertex>> buffer_;
        std::vector<std::pair<Length, Vertex>> prepend_;
        std::set<std::pair<Length, Vertex>> active_;
        Length buffer_min_ = INF;
        Length prepend_min_ = INF;
};

BlockHeap::BlockHeap(int M, Length B) {
    M_ = M;
    B_ = B;
}

std::pair<Length, std::vector<Vertex>> BlockHeap::pull() {
    std::vector<Vertex> S;

    if(active_.empty()) {
        if(!prepend_.empty()) {
            for(auto &p : prepend_) {
                Length l = p.first; Vertex v = p.second;
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }
            prepend_.clear();
            prepend_min_ = INF;
        }

        if(active_.empty() && !buffer_.empty()) {
            int take = std::min((int)buffer_.size(), M_);
            std::nth_element(buffer_.begin(), buffer_.begin() + take, buffer_.end(),
                [](const std::pair<Length, Vertex>& a, const std::pair<Length, Vertex>& b){
                    return a.first < b.first;
                });
            for(int i = 0; i < take; ++i) {
                Length l = buffer_[i].first; Vertex v = buffer_[i].second;
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }

            std::vector<std::pair<Length, Vertex>> newbuf;
            newbuf.reserve(buffer_.size() - take);
            for(size_t i = take; i < buffer_.size(); ++i) newbuf.push_back(buffer_[i]);
            buffer_.swap(newbuf);
            buffer_min_ = INF;
            for(auto &p : buffer_) buffer_min_ = std::min(buffer_min_, p.first);
        }
    }

    for(int i = 0; i < M_; ++i) {
        if(active_.empty()) break;
        auto p = *active_.begin();
        active_.erase(active_.begin());
        Vertex v = p.second; Length l = p.first;
        auto it = d_.find(v);
        if(it != d_.end() && it->second == l) {
            S.push_back(v);
            d_.erase(it);
        }
    }

    Length next_min = INF;
    if(!active_.empty()) next_min = std::min(next_min, active_.begin()->first);
    if(buffer_min_ < next_min) next_min = buffer_min_;
    if(prepend_min_ < next_min) next_min = prepend_min_;
    if(next_min == INF) return std::make_pair(B_, S);
    return std::make_pair(next_min, S);
}

void BlockHeap::batch_prepend(const std::vector<std::pair<Vertex, Length>>& L) {
    for(const auto &p : L) {
        Vertex v = p.first; Length l = p.second;
        auto it = d_.find(v);
        if(it != d_.end()) {
            if(it->second <= l) continue;
            it->second = l;
        } else {
            d_[v] = l;
        }
        prepend_.push_back(std::make_pair(l, v));
        if(l < prepend_min_) prepend_min_ = l;
    }
}

void BlockHeap::insert(Vertex v, Length l) {
    auto it = d_.find(v);
    if(it != d_.end()) {
        if(it->second <= l) return;
        it->second = l;
    } else {
        d_[v] = l;
    }
    buffer_.push_back(std::make_pair(l, v));
    if(l < buffer_min_) buffer_min_ = l;
}

bool BlockHeap::empty() {
    return d_.empty();
}

void BlockHeap::debug() {
    std::cout << "D(active)= [";
    for(auto p: active_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(prepend)= [";
    for(auto &p: prepend_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(buffer)= [";
    for(auto &p: buffer_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class Heap {
    public:
        void push(Vertex v, Length l);
        std::pair<Vertex, Length> top();
        void pop();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        std::set<std::pair<Length, Vertex>> que_;
        std::unordered_map<Vertex, Length> d_;

};

void Heap::push(Vertex v, Length l) {
    if(d_.count(v) != 0 && d_[v] < l) {
        return;
    } else if (d_.count(v) != 0 && d_[v] >= l) {
        que_.erase(std::make_pair(d_[v], v));
    }
    que_.insert(std::make_pair(l, v));
    d_[v] = l;
}

std::pair<Vertex, Length> Heap::top() {
    auto p = *que_.begin();
    return std::make_pair(p.second, p.first);
}

void Heap::pop() {
    d_.erase(top().second);
    que_.erase(que_.begin());
}

bool Heap::empty() {
    return que_.empty();
}

void Heap::debug() {
    std::cout << "H= [";
    for(auto p: que_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class ShortestPath {
    public:
        ShortestPath(Vertex s, const Graph& G);
        std::pair<Length, std::vector<Vertex>> BMSSP(int l, Length B, const std::vector<Vertex>& S);
        std::pair<std::vector<Vertex>, std::vector<Vertex>> find_pivots(Length B, const std::vector<Vertex>& S);
        void print_dhat();

    private:
        int t_;
        int k_;
        std::vector<Length> dhat_;
        Graph G_;

        std::pair<Length, std::vector<Vertex>> base_case(Length B, const std::vector<Vertex>& S);

        std::vector<Vertex> prev_;
        std::vector<int> tree_size_;
        std::vector<std::vector<Vertex>> F_;
};

ShortestPath::ShortestPath(Vertex s, const Graph& G) {
    G_ = G;
    int N = G_.size();
    k_ = std::ceil(pow(std::log2(N), 1.0 / 3.0));
    t_ = std::floor(pow(std::log2(N), 2.0 / 3.0));
    dhat_ = std::vector<Length>(N, INF);
    dhat_[s] = 0;
    prev_ = std::vector<Vertex>(N, -1);
    tree_size_ = std::vector<Vertex>(N, -1);
    F_ = std::vector<std::vector<Vertex>>(N, std::vector<Vertex>());
}

namespace {
    int find_tree_size(int u, std::vector<int>& tree_size, const std::vector<std::vector<Vertex>>& F) {
        if(tree_size[u] != -1) return tree_size[u];
        int res = 1;
        for(int i = 0; i < (int)F[u].size(); i++) {
            Vertex v = F[u][i];
            res += find_tree_size(v, tree_size, F);
        }
        return tree_size[u] = res;
    }

    void debug_vertex_set(std::vector<Vertex> S) {
        std::cout << "[";
        for(int i = 0; i < (int)S.size(); i++) {
            std::cout << S[i] << ", ";
        }
        std::cout << "]" << std::endl;
    }
}

void ShortestPath::print_dhat() {
    for(int i = 0; i < (int)dhat_.size(); i++) {
        if(dhat_[i] == INF) {
            std::cout << "INF" << '\n';
        } else {
            std::cout << dhat_[i] << '\n';
        }
    }
    // std::cout << "[";
    // for(int i = 0; i < (int)dhat_.size(); i++) {
    //     if(dhat_[i] == INF) {
    //         std::cout << "INF" << ", ";
    //     } else {
    //         std::cout << dhat_[i] << ", ";
    //     }
    // }
    // std::cout << "]" << std::endl;
}

std::pair<Length, std::vector<Vertex>> ShortestPath::BMSSP(int l, Length B, const std::vector<Vertex>& S) {
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", S=";
    // debug_vertex_set(S);
    // print_dhat();
    if(l == 0) {
        return base_case(B, S);
    }
    auto pw = find_pivots(B, S);
    std::vector<Vertex> P = pw.first; std::vector<Vertex> W = pw.second;
    // std::cout << "P= "; debug_vertex_set(P);
    // std::cout << "W= "; debug_vertex_set(W);

    int M = std::pow(2, (l - 1) * t_);
    BlockHeap D(M, B);
    Length Bd = INF;
    for(int i = 0; i < (int)P.size(); i++) {
        Vertex u = P[i];
        D.insert(u, dhat_[u]);
        Bd = std::min(Bd, dhat_[u]);
    }
    // D.debug();
    std::unordered_set<Vertex> U;

    while((int)U.size() < k_ * std::pow(2, l * t_) && !D.empty()) {
        auto bs = D.pull();
        Length Bi = bs.first; std::vector<Vertex> Si = bs.second;
        if (Si.empty()) {
            continue; 
        }
        
        auto bu = BMSSP(l - 1, Bi, Si);
        Length Bid = bu.first; std::vector<Vertex> Ui = bu.second;
        // std::cout << "Bid=" << Bid << std::endl;
        // std::cout << "Ui="; debug_vertex_set(Ui);
        // std::cout << "U="; debug_vertex_set(std::vector<Vertex>(U.begin(), U.end()));
        for(int j = 0; j < (int)Ui.size(); j++) {
            // if(U.count(Ui[j]) != 0) {
            //     std::cout << "Ufound" << " " << Ui[j] << " " << dhat_[Ui[j]] << " " << Bi << " " << Bid << std::endl;
            // }
            U.insert(Ui[j]);
        }

        std::vector<std::pair<Vertex, Length>> K;
        for(int j = 0; j < (int)Ui.size(); j++) {
            Vertex u = Ui[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    Length new_dist = dhat_[u] + w;
                    dhat_[v] = new_dist;
                    if(Bi <= new_dist && new_dist < B) {
                        D.insert(v, new_dist);
                    } else if(Bid <= new_dist && new_dist < Bi) {
                        K.push_back(std::make_pair(v, new_dist));
                    }
                }
            }
        }
        for(int i = 0; i < (int)Si.size(); i++) {
            int u = Si[i];
            if(Bid <= dhat_[u] && dhat_[u] < Bi) K.push_back(std::make_pair(u, dhat_[u]));
        }
        D.batch_prepend(K);
        Bd = Bid;
    }
    Bd = std::min(Bd, B);
    for(int i = 0; i < (int)W.size(); i++) {
        Vertex u = W[i];
        if(dhat_[u] < Bd) U.insert(u);
    }
    if(l == 3) {
        for(int i = 0; i < (int)G_.size(); i++) {
            // if(!U.count(i) && dhat_[i] != INF) {
            //     std::cout << "found: " << i << " " << dhat_[i] << std::endl;
            // }
        }
    }
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", Bd=" << Bd << std::endl;
    // std::cout << "U size:=" << U.size() << " " << (D.empty() ? "empty" : "notempty") << std::endl;
    return std::make_pair(Bd, std::vector<Vertex>(U.begin(), U.end()));
}

std::pair<Length, std::vector<Vertex>> ShortestPath::base_case(Length B, const std::vector<Vertex>& S) {
    assert(S.size() == 1);

    Vertex x = S[0];
    // std::cout << "base_case k=" << k_ << ", t=" << t_ << ", B=" << B << ", x=" << x << std::endl; 

    std::unordered_set<Vertex> U0(S.begin(), S.end());
    Heap H;
    H.push(x, dhat_[x]);

    while(!H.empty() && (int)U0.size() < k_ + 1) {
        auto p = H.top(); H.pop();
        Vertex u = p.first; Length d = p.second;
        U0.insert(u);

        for(int i = 0; i < (int)G_[u].size(); i++) {
            int v = G_[u][i].first; Length w = G_[u][i].second;
            if(dhat_[v] >= dhat_[u] + w && dhat_[u] + w < B) {
                dhat_[v] = dhat_[u] + w;
                H.push(v, dhat_[v]);
            }
        }
        // H.debug();
    }

    if((int)U0.size() <= k_) {
        return make_pair(B, std::vector<Vertex>(U0.begin(), U0.end()));
    } else {
        Length Bd = -INF;
        std::vector<Vertex> U;
        for(auto u: U0) {
            Bd = std::max(Bd, dhat_[u]);
        }
        for(auto u: U0) {
            if(dhat_[u] < Bd) {
                U.push_back(u);
            }
        }
        return make_pair(Bd, U);
    }
}


std::pair<std::vector<Vertex>, std::vector<Vertex>> ShortestPath::find_pivots(Length B, const std::vector<Vertex>& S) {
    std::unordered_set<Vertex> W(S.begin(), S.end());
    std::vector<Vertex> Wp = S;

    for(auto v: W) {
        prev_[v] = -1;
    }

    for(int i = 0; i < k_; i++) {
        std::vector<Vertex> Wi; 
        for(int j = 0; j < (int)Wp.size(); j++) {
            Vertex u = Wp[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    dhat_[v] = dhat_[u] + w;
                    prev_[v] = u;
                    // if(dhat_[u] + w < B) {
                        Wi.push_back(v);
                    // }
                }
            }
        }
        for(int k = 0; k < (int)Wi.size(); k++) {
            W.insert(Wi[k]);
        }
        if((int)W.size() >= k_ * (int)S.size()) {
            return std::make_pair(S, std::vector<Vertex>(W.begin(), W.end()));
        }
        Wp = Wi;
        // std::cout << "Wp ="; debug_vertex_set(Wp);
    }

    for(auto v: W) {
        tree_size_[v] = -1;
        F_[v].clear();
    }
    for(auto v: W) {
        Vertex u = prev_[v];
        if(u == -1) continue;
        F_[u].push_back(v);
    }
    std::vector<Vertex> P;
    for(int i = 0; i < (int)S.size(); i++) {
        Vertex u = S[i];
        // std::cout << "find_tree_size: " << u << " " << find_tree_size(u, tree_size_, F_) << std::endl;
        if(find_tree_size(u, tree_size_, F_) >= k_ && prev_[u] == -1) {
            P.push_back(u);
        }
    }
    return std::make_pair(P, std::vector<Vertex>(W.begin(), W.end()));
}




void find_shortest_path(int s, const Graph& G) {
    int N = (int)G.size();
    double t = std::floor(std::pow(std::log2(N), 2.0 / 3.0));
    double l = std::ceil(std::log2(N) / t);
    ShortestPath shortest_path(s, G);
    std::vector<Vertex> S;
    S.push_back(s);
    auto bu = shortest_path.BMSSP(l, INF, S);
    // std::cout << "Bfinal:=" << bu.first << std::endl;
    shortest_path.print_dhat();
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int N, M, s;
    std::cin >> N >> M >> s;
    Graph G(N);
    for(int i = 0; i < M; i++) {
        int a, b; Length c;
        std::cin >> a >> b >> c;
        G[a].push_back(std::make_pair(b, c));
    }
    find_shortest_path(s, G);
    return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 42216
final_rank: 13

code_snippet: #include <iostream>
#include<vector>
#include<list>
#include<utility>
#include<limits>
#include<set>
#include<iostream>
#include<queue>
#include<unordered_map>
#include<unordered_set>
#include<random>
#include<ext/pb_ds/assoc_container.hpp>

using T = long long;
namespace spp {

using namespace std;
using namespace __gnu_pbds;

template<typename K, typename V>
using hash_map = unordered_map<K, V>;
template<typename K>
using hash_set = unordered_set<K>;

template<typename uniqueDistT>
struct batchPQ { // batch priority queue, implemented as in Lemma 3.3
    using elementT = pair<int,uniqueDistT>;
    
    struct CompareUB {
        template <typename It>
        bool operator()(const pair<uniqueDistT, It>& a, const pair<uniqueDistT, It>& b) const {
            if (a.first != b.first) return a.first < b.first;
            return  addressof(*a.second) < addressof(*b.second);
        }
    };
    
    typename list<list<elementT>>::iterator it_min;
    
    list<list<elementT>> D0,D1;
    set<pair<uniqueDistT,typename list<list<elementT>>::iterator>,CompareUB> UBs; // (UB, it_block)
    
    int M,size_;
    uniqueDistT B;
    
    hash_map<int, uniqueDistT> actual_value;
    hash_map<int, pair< typename list<list<elementT>>::iterator , typename list<elementT>::iterator> > where_is[2];
    
    // Initialize
    batchPQ(int M_, uniqueDistT B_): M(M_), B(B_) { // O(1)
        D1.push_back(list<elementT>());
        UBs.insert({B_,D1.begin()});
        size_ = 0;
    }
    
    int size(){
        return size_;
    }
    
    inline void erase(int key) {
        if(actual_value.find(key) != actual_value.end())
            delete_({-1, -1, key, -1});
    }
    void delete_(uniqueDistT x){    
        int a = get<2>(x);
        uniqueDistT b = actual_value[a];
        
        auto it_w = where_is[1].find(a);
        if((it_w != where_is[1].end())){
            auto [it_block,it] = it_w->second;
            
            (*it_block).erase(it);
            where_is[1].erase(a);
    
            if((*it_block).size() == 0){
                auto it_UB_block = UBs.lower_bound({b,it_block});  
                
                if((*it_UB_block).first != B){
                    UBs.erase(it_UB_block);
                    D1.erase(it_block);
                }
            }
        }else{
            auto [it_block,it] = where_is[0][a];
            (*it_block).erase(it);
            where_is[0].erase(a);
            if((*it_block).size() == 0) D0.erase(it_block); 
        }
    
        actual_value.erase(a);
        size_--;
    }
    
    void insert(uniqueDistT x){ // O(lg(Block Numbers))         
        uniqueDistT b = x;
        int a = get<2>(b);
    
        // checking if exists
        auto it_exist = actual_value.find(a);
        int exist = (it_exist != actual_value.end()); 
    
        if(exist && it_exist->second > b){
            delete_(x);
        }else if(exist){
            return;
        }
        
        // Searching for the first block with UB which is > 
        auto it_UB_block = UBs.lower_bound({b,it_min});
        auto [ub,it_block] = (*it_UB_block);
                
        // Inserting key/value (a,b)
        auto it = it_block->insert(it_block->end(),{a,b});
        where_is[1][a] = {it_block, it};
        actual_value[a] = b;
    
        size_++;
    
        // Checking if exceeds the sixe limit M
        if((*it_block).size() > M){
            split(it_block);
        }
    }

    uniqueDistT medianOfMedians(vector<elementT>::iterator bg, vector<elementT>::iterator en) {
        vector<elementT> l(bg, en);
        while (true) {
            int n = l.size();

            if (n <= 5) {
                sort(l.begin(), l.end(), [](const auto& a, const auto& b) {
                    return a.second < b.second;
                });
                return l[l.size() / 2].second;
            }

            vector<elementT> medians;
            medians.reserve((n + 4) / 5);

            auto it = l.begin();
            while (it != l.end()) {
                vector<elementT> group;
                group.reserve(5);
                for (int j = 0; j < 5 && it != l.end(); ++j, ++it)
                    group.push_back(*it);

                sort(group.begin(), group.end(), [](const auto& a, const auto& b) {
                    return a.second < b.second;
                });

                medians.push_back(group[group.size() / 2]);
            }

            l = move(medians);
        }
    }
    
    uniqueDistT selectKth(vector<elementT> &v, int k) { 
        using std::swap;
        int l=0, r=v.size()-1;
        
        for(;l<=r;){
            uniqueDistT p = medianOfMedians(v.begin() + l, v.begin() + r + 1);
            
            int i = l, j = r, m = l;
            
            while(m <= j){
                if(v[m].second < p) {
                    swap(v[m++],v[i++]);
                }else if(v[m].second > p){
                    swap(v[m],v[j--]);
                }else{
                    m++;
                }
            }
        
            if (k < i) r = i - 1;     // k está na parte menor
            else if (k > j) l = j + 1;     // k está na parte maior
            else return v[k].second; // k está entre os iguais ao pivot
        } 
        
        return v[k].second;
    }

        
    void split(list<list<elementT>>::iterator it_block){ // O(M) + O(lg(Block Numbers))
        int sz = (*it_block).size();
        
        vector<elementT> v((*it_block).begin() , (*it_block).end());
        uniqueDistT med = selectKth(v,(sz/2)); // O(M)
        
        auto pos = it_block;
        pos++;


        auto new_block = D1.insert(pos,list<elementT>());
        auto it = (*it_block).begin();
    
        while(it != (*it_block).end()){ // O(M)
            if((*it).second >= med){
                // (*new_block).push_back((*it));
                (*new_block).push_back(move(*it));
                auto it_new = (*new_block).end(); it_new--;
                where_is[1][(*it).first] = {new_block, it_new};
    
                it = (*it_block).erase(it);
            }else{
                it++;
            }
        }
    

        // Updating UBs   
        // O(lg(Block Numbers))
        uniqueDistT UB1 = {get<0>(med),get<1>(med),get<2>(med),get<3>(med)-1};
        auto it_lb = UBs.lower_bound({UB1,it_min});
        auto [UB2,aux] = (*it_lb);
        
        UBs.insert({UB1,it_block});
        UBs.insert({UB2,new_block});
        
        UBs.erase(it_lb);
    }
    
    void batchPrepend(const list<elementT> &l) { // O(|l| log(|l|/M) ) 
        int sz = l.size();
        
        if(sz == 0) return;
        if(sz <= M){
    
            D0.push_front(list<elementT>());
            auto new_block = D0.begin();
            
            for(auto &x : l){ 
                auto it = actual_value.find(x.first);
                int exist = (it != actual_value.end()); 
    
                if(exist && it->second > x.second){
                    delete_(x.second);
                }else if(exist){
                    continue;
                }
    
                (*new_block).push_back(x);
                auto it_new = (*new_block).end(); it_new--;
                where_is[0][x.first] = {new_block, it_new};
                actual_value[x.first] = x.second;
                size_++;
            }
            if(new_block->size() == 0) D0.erase(new_block);
            return;
        }

        vector<elementT> v(l.begin(), l.end());
        uniqueDistT med = selectKth(v, sz/2);
    
        list<elementT> less,great;
        for(auto [a,b]: l){
            if(b < med){
                less.push_back({a,b});
            }else if(b > med){
                great.push_back({a,b});
            }
        }
        
        great.push_back({get<2>(med),med});

        batchPrepend(great);
        batchPrepend(less);
    }
    
    void batchPrepend(const vector<uniqueDistT> &v){
        list<elementT> l;
        for(auto x: v){
            l.push_back({get<2>(x),x});
        }
        batchPrepend(l);
    }
    
    pair<uniqueDistT, vector<int>> pull(){ // O(M)
        vector<elementT> s0,s1;
        s0.reserve(2 * M); s1.reserve(M);
    
        auto it_block = D0.begin();
        while(it_block != D0.end() && s0.size() <= M){ // O(M)   
            for (const auto& x : *it_block) s0.push_back(x);
            it_block++;
        }
    
        it_block = D1.begin();
        while(it_block != D1.end() && s1.size() <= M){   //O(M)
            for (const auto& x : *it_block) s1.push_back(x);
            it_block++;
        }
    
        if(s1.size() + s0.size() <= M){
            vector<int> ret;
            ret.reserve(s1.size()+s0.size());
            for(auto [a,b] : s0) {
                ret.push_back(a);
                delete_({b});
            }
            for(auto [a,b] : s1){
                ret.push_back(a);
                delete_({b});
            } 
    
            return {B, ret};
        }else{  
            vector<elementT> &l = s0;
            l.insert(l.end(), s1.begin(), s1.end());

            uniqueDistT med = selectKth(l, M);
            vector<int> ret;
            ret.reserve(M);
            for(auto [a,b]: l){
                if(b < med) {
                    ret.push_back(a);
                    delete_({b});
                }
            }
            
            return {med,ret};
        }
    }
};

template<typename wT>
struct bmssp { // bmssp class
    int n, k, t;
    const wT oo = numeric_limits<wT>::max() / 10;
 
    vector<vector<pair<int, wT>>> ori_adj;
    vector<vector<pair<int, wT>>> adj;
    vector<wT> d;
    vector<int> pred, path_sz;
    vector<int> rev_map;
    vector<short int> last_complete_lvl;
 
    vector<hash_map<int, int>> neig;
    bmssp(int n_): n(n_) {
        ori_adj.assign(n, {});
        neig.assign(n, {});
    }
    bmssp(const auto &adj) {
        n = adj.size();
        ori_adj = adj;
        neig.assign(n, {});
    }
    void addEdge(int a, int b, wT w) {
        ori_adj[a].emplace_back(b, w);
    }

    // if the graph already has constant degree, prepage_graph(false)
    // else, prepage_graph(true)
    void prepare_graph(bool exec_constant_degree_trasnformation = false) {
        // erase duplicated edges
        vector<pair<int, int>> tmp_edges(n, {-1, -1});
        for(int i = 0; i < n; i++) {
            vector<pair<int, wT>> nw_adj;
            nw_adj.reserve(ori_adj[i].size());
            for(auto [j, w]: ori_adj[i]) {
                if(tmp_edges[j].first != i) {
                    nw_adj.emplace_back(j, w);
                    tmp_edges[j] = {i, nw_adj.size() - 1};
                } else {
                    int id = tmp_edges[j].second;
                    nw_adj[id].second = min(nw_adj[id].second, w);
                }
            }
            ori_adj[i] = move(nw_adj);
        }
        tmp_edges.clear();

        if(exec_constant_degree_trasnformation == false) {
            adj = move(ori_adj);
            ori_adj.clear();
            d.resize(n);
            root.resize(n);
            pred.resize(n);
            treesz.resize(n);
            rev_map.resize(n);
            path_sz.resize(n, 0);
            last_complete_lvl.resize(n);
            
            for(int i = 0; i < n; i++) {
                neig[i][i] = i;
                rev_map[i] = i;
            }

            k = floor(pow(log2(n), 1.0 / 3.0));
            t = floor(pow(log2(n), 2.0 / 3.0));
        } else {
            // Make the graph become constant degree
            int cnt = 0;
            for(int i = 0; i < n; i++) {
                for(auto [j, w]: ori_adj[i]) {
                    if(neig[i].find(j) == neig[i].end()) {
                        neig[i][j] = cnt++;
                        neig[j][i] = cnt++;
                    }
                }
            }

            cnt++;
            adj.assign(cnt, {});
            
            d.resize(cnt);
            root.resize(cnt);
            pred.resize(cnt);
            treesz.resize(cnt);
            rev_map.resize(cnt);
            path_sz.resize(cnt, 0);
            last_complete_lvl.resize(cnt);
    
            for(int i = 0; i < n; i++) { // create 0-weight cycles
                for(auto cur = neig[i].begin(); cur != neig[i].end(); cur++) {
                    auto nxt = next(cur);
                    if(nxt == neig[i].end()) nxt = neig[i].begin();
                    adj[cur->second].emplace_back(nxt->second, wT());
                    rev_map[cur->second] = i;
                }
            }
            for(int i = 0; i < n; i++) { // add edges
                for(auto [j, w]: ori_adj[i]) {
                    adj[neig[i][j]].emplace_back(neig[j][i], w);
                }
                if(neig[i].size() == 0) { // for vertices without edges
                    neig[i][n] = cnt - 1;
                }
            }
            k = floor(pow(log2(cnt), 1.0 / 3.0));
            t = floor(pow(log2(cnt), 2.0 / 3.0));
            
            ori_adj.clear();
        }
    }
    
    int toAnyCustomNode(int real_id) {
        return neig[real_id].begin()->second;
    }
    int customToReal(int id) {
        return rev_map[id];
    }
 
    vector<wT> execute(int s) {
        fill(d.begin(), d.end(), oo);
        fill(path_sz.begin(), path_sz.end(), oo);
        fill(last_complete_lvl.begin(), last_complete_lvl.end(), -1);
        for(int i = 0; i < pred.size(); i++) pred[i] = i;
        
        s = toAnyCustomNode(s);
        d[s] = 0;
        path_sz[s] = 0;
        
        const int l = ceil(log2(adj.size()) / t);
        const uniqueDistT inf_dist = make_tuple(oo, 0, 0, 0);
        bmsspRec(l, inf_dist, {s});
 
        vector<wT> res(n);
        for(int i = 0; i < n; i++) res[i] = d[toAnyCustomNode(i)];
        return res;
    }
    
    // ===================================================================
 
    // set stuff
    // template<typename T>
    // void removeDuplicates(vector<T> &v) { // sort is faster
    //     hash_set<T> s(v.begin(), v.end());
    //     v = vector<T>(s.begin(), s.end());
    //     // sort(v.begin(), v.end());
    //     // v.erase(unique(v.begin(), v.end()), v.end());
    // }
    template<typename T>
    bool isUnique(const vector<T> &v) {
        auto v2 = v;
        sort(v2.begin(), v2.end());
        v2.erase(unique(v2.begin(), v2.end()), v2.end());
        return v2.size() == v.size();
    }

    using uniqueDistT = tuple<wT, int, int, int>;
    inline uniqueDistT getDist(int u, int v, int w) {
        return {d[u] + w, path_sz[u] + 1, v, u};
    }
    inline uniqueDistT getDist(int u) {
        return {d[u], path_sz[u], u, pred[u]};
    }
    void updateDist(int u, int v, wT w) {
        pred[v] = u;
        d[v] = d[u] + w;
        path_sz[v] = path_sz[u] + 1;
    }
    // ===================================================================
    vector<int> root;
    vector<short int> treesz;
    pair<vector<int>, hash_set<int>> findPivots(uniqueDistT B, const vector<int> &S) { // Algorithm 1
        hash_set<int> vis;
        vis.reserve(S.size() * k);
        vis.insert(S.begin(), S.end());

        vector<int> active = S;
        for(int x: S) root[x] = x, treesz[x] = 0;
        for(int i = 1; i <= k; i++) {
            vector<int> nw_active;
            nw_active.reserve(active.size() * 4);
            for(int u: active) {
                for(auto [v, w]: adj[u]) {
                    if(getDist(u, v, w) <= getDist(v)) {
                        updateDist(u, v, w);
                        if(getDist(v) < B) {
                            root[v] = root[u];
                            nw_active.push_back(v);
                        }
                    }
                }
            }
            for(const auto &x: nw_active) {
                vis.insert(x);
            }
            if(vis.size() > k * S.size()) {
                return {S, vis};
            }
            active = move(nw_active);
        }

        vector<int> P;
        P.reserve(vis.size() / k);
        for(int u: vis) treesz[root[u]]++;
        for(int u: S) if(treesz[u] >= k) P.push_back(u);
        
        // assert(P.size() <= vis.size() / k);
        return {P, vis};
    }
 
    pair<uniqueDistT, vector<int>> baseCase(uniqueDistT B, int x) { // Algorithm 2
        vector<int> complete;
        complete.reserve(k + 1);
 
        priority_queue<uniqueDistT, vector<uniqueDistT>, greater<uniqueDistT>> heap;
        heap.push(getDist(x));
        while(heap.empty() == false && complete.size() < k + 1) {
            int u = get<2>(heap.top());
            int du = get<0>(heap.top());
            heap.pop();
            if(du > d[u]) continue;

            complete.push_back(u);
            for(auto [v, w]: adj[u]) {
                auto new_dist = getDist(u, v, w);
                auto old_dist = getDist(v);
                if(new_dist <= old_dist && new_dist < B) {
                    updateDist(u, v, w);
                    heap.push(new_dist);
                }
            }
        }
        if(complete.size() <= k) return {B, complete};
 
        uniqueDistT nB = getDist(complete.back());
        // {   // sanity check
        //     int cntbig = 0;
        //     for(int u: complete) if(getDist(u) >= nB) cntbig++;
        //     assert(cntbig == 1);
        //     for(int u: complete) assert(getDist(u) < B);
        //     assert(complete.size() == k + 1);
        // }
        complete.pop_back();
        return {nB, complete};
    }
 
    pair<uniqueDistT, vector<int>> bmsspRec(short int l, uniqueDistT B, const vector<int> &S) { // Algorithm 3
        if(l == 0) return baseCase(B, S[0]);
 
        auto [P, bellman_vis] = findPivots(B, S);
 
        const long long batch_size = (1ll << ((l - 1) * t));
        batchPQ<uniqueDistT> D(batch_size, B);
        for(int p: P) D.insert(getDist(p));
 
        uniqueDistT last_complete_B = B;
        for(int p: P) last_complete_B = min(last_complete_B, getDist(p));
 
        vector<int> complete;
        const long long quota = k * (1ll << (l * t));
        complete.reserve(quota + bellman_vis.size());
        while(complete.size() < quota && D.size()) {
            auto [trying_B, miniS] = D.pull();
            // all with dist < trying_B, can be reached by miniS <= req 2, alg 3
 
            auto [complete_B, nw_complete] = bmsspRec(l - 1, trying_B, miniS);
            
            // all new complete_B are greater than the old ones <= point 6, page 10
            // assert(last_complete_B < complete_B);
 
            complete.insert(complete.end(), nw_complete.begin(), nw_complete.end());
            // point 6, page 10 => complete does not intersect with nw_complete
            // assert(isUnique(complete));
 
            vector<uniqueDistT> can_prepend;
            can_prepend.reserve(nw_complete.size() * 5 + miniS.size());
            for(int u: nw_complete) {
                D.erase(u); // priority queue fix
                last_complete_lvl[u] = l;
                for(auto [v, w]: adj[u]) {
                    auto new_dist = getDist(u, v, w);
                    if(new_dist <= getDist(v)) {
                        updateDist(u, v, w);
                        if(trying_B <= new_dist && new_dist < B) {
                            D.insert(new_dist); // d[v] can be greater equal than min(D), occur 1x per vertex
                        } else if(complete_B <= new_dist && new_dist < trying_B) {
                            can_prepend.emplace_back(new_dist); // d[v] is less than all in D, can occur 1x at each level per vertex
                        }
                    }
                }
            }
            for(int x: miniS) {
                if(complete_B <= getDist(x)) can_prepend.emplace_back(getDist(x));
                // second condition is not necessary
            }
            // can_prepend is not necessarily all unique
            D.batchPrepend(can_prepend);
 
            last_complete_B = complete_B;
        }
        uniqueDistT retB;
        if(D.size() == 0) retB = B;     // successful
        else retB = last_complete_B;    // partial
 
        for(int x: bellman_vis) if(last_complete_lvl[x] != l && getDist(x) < retB) complete.push_back(x); // this get the completed vertices from bellman-ford, it has P in it as well
        // get only the ones not in complete already, for it to become disjoint
 
        return {retB, complete};
    }
};
}

int main() {
    int n, m, s;
    std::cin >> n >> m >> s;
    std::vector<std::tuple<int, int, T>> edges;
    while (m --)
    {
        int u, v, w;
        std::cin >> u >> v >> w;
        edges.push_back({u, v, w});
    }
    
    // std::vector<std::tuple<int, int, T>> edges = {
    //     {0, 1, 10}, {0, 2, 3}, {1, 3, 2}, {2, 1, 4},
    //     {2, 3, 8}, {2, 4, 2}, {3, 4, 5}
    // };
    int source_node = s;

    // 2. Initialize and build the graph
    spp::bmssp<T> solver(n);
    for (const auto& [u, v, weight] : edges) {
        solver.addEdge(u, v, weight);
    }

    // 3. Prepare the graph (must be called once)
    solver.prepare_graph(false);
    // use solver.prepare_graph(true) if the graph does not have contant out-degree

    // 4. Compute shortest paths
    std::vector<T> distances = solver.execute(source_node);

    // 5. Print results
    // std::cout << "Shortest paths from source " << source_node << ":" << std::endl;
    for (int i = 0; i < n; ++i) {
        if (distances[i] == solver.oo) {
            std::cout << "INF" << '\n';
        } else {
            std::cout << distances[i] << '\n';
        }
    }

    return 0;
}
accuracy: 1
time_ms: 300
memory_kb: 56532
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define oke cout << "Yes" << '\n';
#define dame cout << "No" << '\n';
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
using Hai2 = vector<vector<ll>>;
using HaiW = vector<vector<pair<ll,ll>>>;
using HaiB = vector<vector<bool>>;
using Hai3 = vector<vector<vector<ll>>>;


int main() {
	cout << fixed << setprecision(15);
    ll N,M,R;
    cin>>N>>M>>R;
    vector<vector<pair<ll,ll>>> G(N);
    rep(i,M){
        ll a,b,c;
        cin>>a>>b>>c;
        G[a].push_back({b,c});
    }

    queue<int>Q;
    vector<ll>dist(N,1e9);

    Q.push(R);
    dist[R]=0;

    while(!Q.empty()){
        int v = Q.front();
        Q.pop();
        for(auto x:G[v]){
            if(dist[x.first]>dist[v]+x.second){
                dist[x.first]=dist[v]+x.second;
                Q.push(x.first);
            }
        }
    }

    rep(i,N){
        if(dist[i]!=1e9){
            cout<<dist[i]<<endl;
        }else{
            cout<<"INF"<<endl;
        }
    }
}
accuracy: 1
time_ms: 300
memory_kb: 17756
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using ll=long long;
const ll INF=1ll<<60;
int main(){
    int v,e,r;
    cin>>v>>e>>r;
        vector<vector<pair<int,int>>>g(v,vector<pair<int,int>>());
        rep(i,e){
            int s,t,d;
            cin>>s>>t>>d;
            g[s].push_back({t,d});
        }
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
        q.push({0,r});
        vector<int>dist(v,2e9);
        dist[r]=0;
        while(!q.empty()){
            auto [a,v]=q.top();
            q.pop();
            for(auto [next_v,cost]:g[v]){
                if(dist[next_v]>dist[v]+cost){
                    dist[next_v]=dist[v]+cost;
                    q.push({dist[next_v],next_v});
                }
            }
        }
        for(auto p:dist){
            if(p!=2e9)cout<<p<<endl;
            else cout<<"INF"<<endl;
        }
    return 0;
}
accuracy: 1
time_ms: 300
memory_kb: 13144
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <queue>

struct Edge
{
	int to; // 接続先ノードのID
	long long cost; // 接続先ノードまでのコスト

	Edge(int to, long long cost)
	{
		this->to = to;
		this->cost = cost;
	}

	bool operator>(const Edge& other) const
	{
		return this->cost > other.cost;
	}
};

using Graph = std::vector<std::vector<Edge>>;
constexpr long long INF = 1LL << 60;

void Dijkstra(const Graph& graph, std::vector<long long>& dist, int start)
{
	std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge>> queue;
	dist.assign(graph.size(), INF);

	dist[start] = 0;
	queue.push({start, 0});

	while (!queue.empty()) {
		Edge edge = queue.top();
		queue.pop();
		if (edge.cost > dist[edge.to]) {
			continue;
		}
		for (const Edge& e : graph[edge.to]) {
			long long nextDist = dist[edge.to] + e.cost;
			if (nextDist < dist[e.to]) {
				dist[e.to] = nextDist;
				queue.push({e.to, nextDist});
			}
		}
	}
}

int main()
{
	int V, E, r;
	std::cin >> V >> E >> r;
	Graph graph(V);
	for (int i = 0; i < E; ++i) {
		int from, to, cost;
		std::cin >> from >> to >> cost;
		graph[from].push_back({to, cost});
	}

	std::vector<long long> dist;
	Dijkstra(graph, dist, r);

	for (int i = 0; i < V; ++i) {
		if (dist[i] == INF) {
			std::cout << "INF" << std::endl;

		}
		else {
			std::cout << dist[i] << std::endl;
		}
	}
}
accuracy: 1
time_ms: 310
memory_kb: 19672
final_rank: 12

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#include <iostream>
#include <vector>
#include <cmath>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <limits>
#include <map>
#include <algorithm>
#include <cassert>

using Vertex = int;
using Length = long long;
const Length INF = std::numeric_limits<long long>::max();
using Edge = std::pair<Vertex, Length>;
using Graph = std::vector<std::vector<Edge>>;

class BlockHeap {
    public:
        BlockHeap(int M, Length B);
        void insert(Vertex v, Length l);
        void batch_prepend(const std::vector<std::pair<Vertex, Length>>& L);
        std::pair<Length ,std::vector<Vertex>> pull();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        std::set<std::pair<Length, Vertex>> que_;
        std::unordered_map<Vertex, Length> d_;
};

BlockHeap::BlockHeap(int M, Length B) {
    M_ = M;
    B_ = B;
}

std::pair<Length, std::vector<Vertex>> BlockHeap::pull() {
    std::vector<Vertex> S;
    for(int i = 0; i < M_; i++) {
        if(que_.empty()) {
            break;
        }
        std::pair<Length, Vertex> p = *que_.begin();
        que_.erase(p);
        d_.erase(p.second);
        S.push_back(p.second);
    }
    if(que_.empty()) {
        return std::make_pair(B_, S);
    } else {
        return std::make_pair(que_.begin()->first, S);
    }
}

void BlockHeap::batch_prepend(const std::vector<std::pair<Vertex, Length>>& L) {
    for(int i = 0; i < (int)L.size(); i++) {
        insert(L[i].first, L[i].second);
    }
}

void BlockHeap::insert(Vertex v, Length l) {
    if(d_.count(v) != 0 && d_[v] < l) {
        return;
    } else if (d_.count(v) != 0 && d_[v] >= l) {
        que_.erase(std::make_pair(d_[v], v));
    }
    que_.insert(std::make_pair(l, v));
    d_[v] = l;
}

bool BlockHeap::empty() {
    return que_.empty();
}

void BlockHeap::debug() {
    std::cout << "D= [";
    for(auto p: que_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class Heap {
    public:
        void push(Vertex v, Length l);
        std::pair<Vertex, Length> top();
        void pop();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        std::set<std::pair<Length, Vertex>> que_;
        std::unordered_map<Vertex, Length> d_;

};

void Heap::push(Vertex v, Length l) {
    if(d_.count(v) != 0 && d_[v] < l) {
        return;
    } else if (d_.count(v) != 0 && d_[v] >= l) {
        que_.erase(std::make_pair(d_[v], v));
    }
    que_.insert(std::make_pair(l, v));
    d_[v] = l;
}

std::pair<Vertex, Length> Heap::top() {
    auto p = *que_.begin();
    return std::make_pair(p.second, p.first);
}

void Heap::pop() {
    d_.erase(top().second);
    que_.erase(que_.begin());
}

bool Heap::empty() {
    return que_.empty();
}

void Heap::debug() {
    std::cout << "H= [";
    for(auto p: que_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class ShortestPath {
    public:
        ShortestPath(Vertex s, const Graph& G);
        std::pair<Length, std::vector<Vertex>> BMSSP(int l, Length B, const std::vector<Vertex>& S);
        std::pair<std::vector<Vertex>, std::vector<Vertex>> find_pivots(Length B, const std::vector<Vertex>& S);
        void print_dhat();

    private:
        int t_;
        int k_;
        std::vector<Length> dhat_;
        Graph G_;

        std::pair<Length, std::vector<Vertex>> base_case(Length B, const std::vector<Vertex>& S);

        std::vector<Vertex> prev_;
        std::vector<int> tree_size_;
        std::vector<std::vector<Vertex>> F_;
};

ShortestPath::ShortestPath(Vertex s, const Graph& G) {
    G_ = G;
    int N = G_.size();
    k_ = std::ceil(pow(std::log2(N), 1.0 / 3.0));
    t_ = std::floor(pow(std::log2(N), 2.0 / 3.0));
    dhat_ = std::vector<Length>(N, INF);
    dhat_[s] = 0;
    prev_ = std::vector<Vertex>(N, -1);
    tree_size_ = std::vector<Vertex>(N, -1);
    F_ = std::vector<std::vector<Vertex>>(N, std::vector<Vertex>());
}

namespace {
    int find_tree_size(int u, std::vector<int>& tree_size, const std::vector<std::vector<Vertex>>& F) {
        if(tree_size[u] != -1) return tree_size[u];
        int res = 1;
        for(int i = 0; i < (int)F[u].size(); i++) {
            Vertex v = F[u][i];
            res += find_tree_size(v, tree_size, F);
        }
        return tree_size[u] = res;
    }

    void debug_vertex_set(std::vector<Vertex> S) {
        std::cout << "[";
        for(int i = 0; i < (int)S.size(); i++) {
            std::cout << S[i] << ", ";
        }
        std::cout << "]" << std::endl;
    }
}

void ShortestPath::print_dhat() {
    for(int i = 0; i < (int)dhat_.size(); i++) {
        if(dhat_[i] == INF) {
            std::cout << "INF" << '\n';
        } else {
            std::cout << dhat_[i] << '\n';
        }
    }
    // std::cout << "[";
    // for(int i = 0; i < (int)dhat_.size(); i++) {
    //     if(dhat_[i] == INF) {
    //         std::cout << "INF" << ", ";
    //     } else {
    //         std::cout << dhat_[i] << ", ";
    //     }
    // }
    // std::cout << "]" << std::endl;
}

std::pair<Length, std::vector<Vertex>> ShortestPath::BMSSP(int l, Length B, const std::vector<Vertex>& S) {
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", S=";
    // debug_vertex_set(S);
    // print_dhat();
    if(l == 0) {
        return base_case(B, S);
    }
    auto pw = find_pivots(B, S);
    std::vector<Vertex> P = pw.first; std::vector<Vertex> W = pw.second;
    // std::cout << "P= "; debug_vertex_set(P);
    // std::cout << "W= "; debug_vertex_set(W);

    int M = std::pow(2, (l - 1) * t_);
    BlockHeap D(M, B);
    Length Bd = INF;
    for(int i = 0; i < (int)P.size(); i++) {
        Vertex u = P[i];
        D.insert(u, dhat_[u]);
        Bd = std::min(Bd, dhat_[u]);
    }
    // D.debug();
    std::unordered_set<Vertex> U;

    while((int)U.size() < k_ * std::pow(2, l * t_) && !D.empty()) {
        auto bs = D.pull();
        Length Bi = bs.first; std::vector<Vertex> Si = bs.second;
        auto bu = BMSSP(l - 1, Bi, Si);
        Length Bid = bu.first; std::vector<Vertex> Ui = bu.second;
        // std::cout << "Bid=" << Bid << std::endl;
        // std::cout << "Ui="; debug_vertex_set(Ui);
        // std::cout << "U="; debug_vertex_set(std::vector<Vertex>(U.begin(), U.end()));
        for(int j = 0; j < (int)Ui.size(); j++) {
            // if(U.count(Ui[j]) != 0) {
            //     std::cout << "Ufound" << " " << Ui[j] << " " << dhat_[Ui[j]] << " " << Bi << " " << Bid << std::endl;
            // }
            U.insert(Ui[j]);
        }

        std::vector<std::pair<Vertex, Length>> K;
        for(int j = 0; j < (int)Ui.size(); j++) {
            Vertex u = Ui[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    Length new_dist = dhat_[u] + w;
                    dhat_[v] = new_dist;
                    if(Bi <= new_dist && new_dist < B) {
                        D.insert(v, new_dist);
                    } else if(Bid <= new_dist && new_dist < Bi) {
                        K.push_back(std::make_pair(v, new_dist));
                    }
                }
            }
        }
        for(int i = 0; i < (int)Si.size(); i++) {
            int u = Si[i];
            if(Bid <= dhat_[u] && dhat_[u] < Bi) K.push_back(std::make_pair(u, dhat_[u]));
        }
        D.batch_prepend(K);
        Bd = Bid;
    }
    Bd = std::min(Bd, B);
    for(int i = 0; i < (int)W.size(); i++) {
        Vertex u = W[i];
        if(dhat_[u] < Bd) U.insert(u);
    }
    if(l == 3) {
        for(int i = 0; i < (int)G_.size(); i++) {
            // if(!U.count(i) && dhat_[i] != INF) {
            //     std::cout << "found: " << i << " " << dhat_[i] << std::endl;
            // }
        }
    }
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", Bd=" << Bd << std::endl;
    // std::cout << "U size:=" << U.size() << " " << (D.empty() ? "empty" : "notempty") << std::endl;
    return std::make_pair(Bd, std::vector<Vertex>(U.begin(), U.end()));
}

std::pair<Length, std::vector<Vertex>> ShortestPath::base_case(Length B, const std::vector<Vertex>& S) {
    assert(S.size() == 1);

    Vertex x = S[0];
    // std::cout << "base_case k=" << k_ << ", t=" << t_ << ", B=" << B << ", x=" << x << std::endl; 

    std::unordered_set<Vertex> U0(S.begin(), S.end());
    Heap H;
    H.push(x, dhat_[x]);

    while(!H.empty() && (int)U0.size() < k_ + 1) {
        auto p = H.top(); H.pop();
        Vertex u = p.first; Length d = p.second;
        U0.insert(u);

        for(int i = 0; i < (int)G_[u].size(); i++) {
            int v = G_[u][i].first; Length w = G_[u][i].second;
            if(dhat_[v] >= dhat_[u] + w && dhat_[u] + w < B) {
                dhat_[v] = dhat_[u] + w;
                H.push(v, dhat_[v]);
            }
        }
        // H.debug();
    }

    if((int)U0.size() <= k_) {
        return make_pair(B, std::vector<Vertex>(U0.begin(), U0.end()));
    } else {
        Length Bd = -INF;
        std::vector<Vertex> U;
        for(auto u: U0) {
            Bd = std::max(Bd, dhat_[u]);
        }
        for(auto u: U0) {
            if(dhat_[u] < Bd) {
                U.push_back(u);
            }
        }
        return make_pair(Bd, U);
    }
}


std::pair<std::vector<Vertex>, std::vector<Vertex>> ShortestPath::find_pivots(Length B, const std::vector<Vertex>& S) {
    std::unordered_set<Vertex> W(S.begin(), S.end());
    std::vector<Vertex> Wp = S;

    for(auto v: W) {
        prev_[v] = -1;
    }

    for(int i = 0; i < k_; i++) {
        std::vector<Vertex> Wi; 
        for(int j = 0; j < (int)Wp.size(); j++) {
            Vertex u = Wp[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    dhat_[v] = dhat_[u] + w;
                    prev_[v] = u;
                    // if(dhat_[u] + w < B) {
                        Wi.push_back(v);
                    // }
                }
            }
        }
        for(int k = 0; k < (int)Wi.size(); k++) {
            W.insert(Wi[k]);
        }
        if((int)W.size() >= k_ * (int)S.size()) {
            return std::make_pair(S, std::vector<Vertex>(W.begin(), W.end()));
        }
        Wp = Wi;
        // std::cout << "Wp ="; debug_vertex_set(Wp);
    }

    for(auto v: W) {
        tree_size_[v] = -1;
        F_[v].clear();
    }
    for(auto v: W) {
        Vertex u = prev_[v];
        if(u == -1) continue;
        F_[u].push_back(v);
    }
    std::vector<Vertex> P;
    for(int i = 0; i < (int)S.size(); i++) {
        Vertex u = S[i];
        // std::cout << "find_tree_size: " << u << " " << find_tree_size(u, tree_size_, F_) << std::endl;
        if(find_tree_size(u, tree_size_, F_) >= k_ && prev_[u] == -1) {
            P.push_back(u);
        }
    }
    return std::make_pair(P, std::vector<Vertex>(W.begin(), W.end()));
}




void find_shortest_path(int s, const Graph& G) {
    int N = (int)G.size();
    double t = std::floor(std::pow(std::log2(N), 2.0 / 3.0));
    double l = std::ceil(std::log2(N) / t);
    ShortestPath shortest_path(s, G);
    std::vector<Vertex> S;
    S.push_back(s);
    auto bu = shortest_path.BMSSP(l, INF, S);
    // std::cout << "Bfinal:=" << bu.first << std::endl;
    shortest_path.print_dhat();
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int N, M, s;
    std::cin >> N >> M >> s;
    Graph G(N);
    for(int i = 0; i < M; i++) {
        int a, b; Length c;
        std::cin >> a >> b >> c;
        G[a].push_back(std::make_pair(b, c));
    }
    find_shortest_path(s, G);
    return 0;
}
accuracy: 1
time_ms: 300
memory_kb: 39840
final_rank: 14

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#include <iostream>
#include <vector>
#include <cmath>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <limits>
#include <map>
#include <algorithm>
#include <cassert>

using Vertex = int;
using Length = long long;
const Length INF = std::numeric_limits<long long>::max();
using Edge = std::pair<Vertex, Length>;
using Graph = std::vector<std::vector<Edge>>;

class BlockHeap {
    public:
        BlockHeap(int M, Length B);
        void insert(Vertex v, Length l);
        void batch_prepend(const std::vector<std::pair<Vertex, Length>>& L);
        std::pair<Length ,std::vector<Vertex>> pull();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        // We implement a buffered block-heap: new inserts go to an append buffer (buffer_),
        // batch_prepend items go to a prepend buffer (prepend_), and we maintain a small
        // active sorted set (active_) from which we pop up to M elements per pull.
        // We keep a map d_ of current best distances for vertices; entries in buffers
        // may be stale and are validated against d_ on extraction.

        std::unordered_map<Vertex, Length> d_;
        std::vector<std::pair<Length, Vertex>> buffer_; // append-only buffer (length, vertex)
        std::vector<std::pair<Length, Vertex>> prepend_; // items to prioritize
        std::set<std::pair<Length, Vertex>> active_; // sorted active set
        Length buffer_min_ = INF;
        Length prepend_min_ = INF;
};

BlockHeap::BlockHeap(int M, Length B) {
    M_ = M;
    B_ = B;
}

std::pair<Length, std::vector<Vertex>> BlockHeap::pull() {
    std::vector<Vertex> S;

    // Ensure active_ has elements to pop, preferring prepend_ then buffer_.
    if(active_.empty()) {
        // Move all prepend_ items into active_
        if(!prepend_.empty()) {
            for(auto &p : prepend_) {
                Length l = p.first; Vertex v = p.second;
                // only insert if this entry is current
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }
            prepend_.clear();
            prepend_min_ = INF;
        }
        // If still empty, move up to M_ smallest from buffer_
        if(active_.empty() && !buffer_.empty()) {
            int take = std::min((int)buffer_.size(), M_);
            // partial sort: nth_element to partition smallest 'take' elements
            std::nth_element(buffer_.begin(), buffer_.begin() + take, buffer_.end(),
                [](const std::pair<Length, Vertex>& a, const std::pair<Length, Vertex>& b){
                    return a.first < b.first;
                });
            // move the first 'take' items into active_
            for(int i = 0; i < take; ++i) {
                Length l = buffer_[i].first; Vertex v = buffer_[i].second;
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }
            // rebuild buffer_ with remaining items
            std::vector<std::pair<Length, Vertex>> newbuf;
            newbuf.reserve(buffer_.size() - take);
            for(size_t i = take; i < buffer_.size(); ++i) newbuf.push_back(buffer_[i]);
            buffer_.swap(newbuf);
            // recompute buffer_min_
            buffer_min_ = INF;
            for(auto &p : buffer_) buffer_min_ = std::min(buffer_min_, p.first);
        }
    }

    // Pop up to M_ items from active_
    for(int i = 0; i < M_; ++i) {
        if(active_.empty()) break;
        auto p = *active_.begin();
        active_.erase(active_.begin());
        Vertex v = p.second; Length l = p.first;
        auto it = d_.find(v);
        if(it != d_.end() && it->second == l) {
            // valid
            S.push_back(v);
            d_.erase(it);
        }
        // otherwise stale, skip
    }

    // compute next threshold Bi
    Length next_min = INF;
    if(!active_.empty()) next_min = std::min(next_min, active_.begin()->first);
    if(buffer_min_ < next_min) next_min = buffer_min_;
    if(prepend_min_ < next_min) next_min = prepend_min_;
    if(next_min == INF) return std::make_pair(B_, S);
    return std::make_pair(next_min, S);
}

void BlockHeap::batch_prepend(const std::vector<std::pair<Vertex, Length>>& L) {
    // batch prepend: add items to prepend_ (higher priority than buffer_)
    for(const auto &p : L) {
        Vertex v = p.first; Length l = p.second;
        auto it = d_.find(v);
        if(it != d_.end()) {
            if(it->second <= l) continue;
            // update to better value
            it->second = l;
        } else {
            d_[v] = l;
        }
        prepend_.push_back(std::make_pair(l, v));
        if(l < prepend_min_) prepend_min_ = l;
    }
}

void BlockHeap::insert(Vertex v, Length l) {
    auto it = d_.find(v);
    if(it != d_.end()) {
        if(it->second <= l) return; // no improvement
        it->second = l;
    } else {
        d_[v] = l;
    }
    buffer_.push_back(std::make_pair(l, v));
    if(l < buffer_min_) buffer_min_ = l;
}

bool BlockHeap::empty() {
    return d_.empty();
}

void BlockHeap::debug() {
    std::cout << "D(active)= [";
    for(auto p: active_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(prepend)= [";
    for(auto &p: prepend_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(buffer)= [";
    for(auto &p: buffer_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class Heap {
    public:
        void push(Vertex v, Length l);
        std::pair<Vertex, Length> top();
        void pop();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        std::set<std::pair<Length, Vertex>> que_;
        std::unordered_map<Vertex, Length> d_;

};

void Heap::push(Vertex v, Length l) {
    if(d_.count(v) != 0 && d_[v] < l) {
        return;
    } else if (d_.count(v) != 0 && d_[v] >= l) {
        que_.erase(std::make_pair(d_[v], v));
    }
    que_.insert(std::make_pair(l, v));
    d_[v] = l;
}

std::pair<Vertex, Length> Heap::top() {
    auto p = *que_.begin();
    return std::make_pair(p.second, p.first);
}

void Heap::pop() {
    d_.erase(top().second);
    que_.erase(que_.begin());
}

bool Heap::empty() {
    return que_.empty();
}

void Heap::debug() {
    std::cout << "H= [";
    for(auto p: que_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class ShortestPath {
    public:
        ShortestPath(Vertex s, const Graph& G);
        std::pair<Length, std::vector<Vertex>> BMSSP(int l, Length B, const std::vector<Vertex>& S);
        std::pair<std::vector<Vertex>, std::vector<Vertex>> find_pivots(Length B, const std::vector<Vertex>& S);
        void print_dhat();

    private:
        int t_;
        int k_;
        std::vector<Length> dhat_;
        Graph G_;

        std::pair<Length, std::vector<Vertex>> base_case(Length B, const std::vector<Vertex>& S);

        std::vector<Vertex> prev_;
        std::vector<int> tree_size_;
        std::vector<std::vector<Vertex>> F_;
};

ShortestPath::ShortestPath(Vertex s, const Graph& G) {
    G_ = G;
    int N = G_.size();
    k_ = std::ceil(pow(std::log2(N), 1.0 / 3.0));
    t_ = std::floor(pow(std::log2(N), 2.0 / 3.0));
    dhat_ = std::vector<Length>(N, INF);
    dhat_[s] = 0;
    prev_ = std::vector<Vertex>(N, -1);
    tree_size_ = std::vector<Vertex>(N, -1);
    F_ = std::vector<std::vector<Vertex>>(N, std::vector<Vertex>());
}

namespace {
    int find_tree_size(int u, std::vector<int>& tree_size, const std::vector<std::vector<Vertex>>& F) {
        if(tree_size[u] != -1) return tree_size[u];
        int res = 1;
        for(int i = 0; i < (int)F[u].size(); i++) {
            Vertex v = F[u][i];
            res += find_tree_size(v, tree_size, F);
        }
        return tree_size[u] = res;
    }

    void debug_vertex_set(std::vector<Vertex> S) {
        std::cout << "[";
        for(int i = 0; i < (int)S.size(); i++) {
            std::cout << S[i] << ", ";
        }
        std::cout << "]" << std::endl;
    }
}

void ShortestPath::print_dhat() {
    for(int i = 0; i < (int)dhat_.size(); i++) {
        if(dhat_[i] == INF) {
            std::cout << "INF" << '\n';
        } else {
            std::cout << dhat_[i] << '\n';
        }
    }
    // std::cout << "[";
    // for(int i = 0; i < (int)dhat_.size(); i++) {
    //     if(dhat_[i] == INF) {
    //         std::cout << "INF" << ", ";
    //     } else {
    //         std::cout << dhat_[i] << ", ";
    //     }
    // }
    // std::cout << "]" << std::endl;
}

std::pair<Length, std::vector<Vertex>> ShortestPath::BMSSP(int l, Length B, const std::vector<Vertex>& S) {
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", S=";
    // debug_vertex_set(S);
    // print_dhat();
    if(l == 0) {
        return base_case(B, S);
    }
    auto pw = find_pivots(B, S);
    std::vector<Vertex> P = pw.first; std::vector<Vertex> W = pw.second;
    // std::cout << "P= "; debug_vertex_set(P);
    // std::cout << "W= "; debug_vertex_set(W);

    int M = std::pow(2, (l - 1) * t_);
    BlockHeap D(M, B);
    Length Bd = INF;
    for(int i = 0; i < (int)P.size(); i++) {
        Vertex u = P[i];
        D.insert(u, dhat_[u]);
        Bd = std::min(Bd, dhat_[u]);
    }
    // D.debug();
    std::unordered_set<Vertex> U;

    while((int)U.size() < k_ * std::pow(2, l * t_) && !D.empty()) {
        auto bs = D.pull();
        Length Bi = bs.first; std::vector<Vertex> Si = bs.second;
        if (Si.empty()) {
            continue; 
        }
        
        auto bu = BMSSP(l - 1, Bi, Si);
        Length Bid = bu.first; std::vector<Vertex> Ui = bu.second;
        // std::cout << "Bid=" << Bid << std::endl;
        // std::cout << "Ui="; debug_vertex_set(Ui);
        // std::cout << "U="; debug_vertex_set(std::vector<Vertex>(U.begin(), U.end()));
        for(int j = 0; j < (int)Ui.size(); j++) {
            // if(U.count(Ui[j]) != 0) {
            //     std::cout << "Ufound" << " " << Ui[j] << " " << dhat_[Ui[j]] << " " << Bi << " " << Bid << std::endl;
            // }
            U.insert(Ui[j]);
        }

        std::vector<std::pair<Vertex, Length>> K;
        for(int j = 0; j < (int)Ui.size(); j++) {
            Vertex u = Ui[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    Length new_dist = dhat_[u] + w;
                    dhat_[v] = new_dist;
                    if(Bi <= new_dist && new_dist < B) {
                        D.insert(v, new_dist);
                    } else if(Bid <= new_dist && new_dist < Bi) {
                        K.push_back(std::make_pair(v, new_dist));
                    }
                }
            }
        }
        for(int i = 0; i < (int)Si.size(); i++) {
            int u = Si[i];
            if(Bid <= dhat_[u] && dhat_[u] < Bi) K.push_back(std::make_pair(u, dhat_[u]));
        }
        D.batch_prepend(K);
        Bd = Bid;
    }
    Bd = std::min(Bd, B);
    for(int i = 0; i < (int)W.size(); i++) {
        Vertex u = W[i];
        if(dhat_[u] < Bd) U.insert(u);
    }
    if(l == 3) {
        for(int i = 0; i < (int)G_.size(); i++) {
            // if(!U.count(i) && dhat_[i] != INF) {
            //     std::cout << "found: " << i << " " << dhat_[i] << std::endl;
            // }
        }
    }
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", Bd=" << Bd << std::endl;
    // std::cout << "U size:=" << U.size() << " " << (D.empty() ? "empty" : "notempty") << std::endl;
    return std::make_pair(Bd, std::vector<Vertex>(U.begin(), U.end()));
}

std::pair<Length, std::vector<Vertex>> ShortestPath::base_case(Length B, const std::vector<Vertex>& S) {
    assert(S.size() == 1);

    Vertex x = S[0];
    // std::cout << "base_case k=" << k_ << ", t=" << t_ << ", B=" << B << ", x=" << x << std::endl; 

    std::unordered_set<Vertex> U0(S.begin(), S.end());
    Heap H;
    H.push(x, dhat_[x]);

    while(!H.empty() && (int)U0.size() < k_ + 1) {
        auto p = H.top(); H.pop();
        Vertex u = p.first; Length d = p.second;
        U0.insert(u);

        for(int i = 0; i < (int)G_[u].size(); i++) {
            int v = G_[u][i].first; Length w = G_[u][i].second;
            if(dhat_[v] >= dhat_[u] + w && dhat_[u] + w < B) {
                dhat_[v] = dhat_[u] + w;
                H.push(v, dhat_[v]);
            }
        }
        // H.debug();
    }

    if((int)U0.size() <= k_) {
        return make_pair(B, std::vector<Vertex>(U0.begin(), U0.end()));
    } else {
        Length Bd = -INF;
        std::vector<Vertex> U;
        for(auto u: U0) {
            Bd = std::max(Bd, dhat_[u]);
        }
        for(auto u: U0) {
            if(dhat_[u] < Bd) {
                U.push_back(u);
            }
        }
        return make_pair(Bd, U);
    }
}


std::pair<std::vector<Vertex>, std::vector<Vertex>> ShortestPath::find_pivots(Length B, const std::vector<Vertex>& S) {
    std::unordered_set<Vertex> W(S.begin(), S.end());
    std::vector<Vertex> Wp = S;

    for(auto v: W) {
        prev_[v] = -1;
    }

    for(int i = 0; i < k_; i++) {
        std::vector<Vertex> Wi; 
        for(int j = 0; j < (int)Wp.size(); j++) {
            Vertex u = Wp[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    dhat_[v] = dhat_[u] + w;
                    prev_[v] = u;
                    // if(dhat_[u] + w < B) {
                        Wi.push_back(v);
                    // }
                }
            }
        }
        for(int k = 0; k < (int)Wi.size(); k++) {
            W.insert(Wi[k]);
        }
        if((int)W.size() >= k_ * (int)S.size()) {
            return std::make_pair(S, std::vector<Vertex>(W.begin(), W.end()));
        }
        Wp = Wi;
        // std::cout << "Wp ="; debug_vertex_set(Wp);
    }

    for(auto v: W) {
        tree_size_[v] = -1;
        F_[v].clear();
    }
    for(auto v: W) {
        Vertex u = prev_[v];
        if(u == -1) continue;
        F_[u].push_back(v);
    }
    std::vector<Vertex> P;
    for(int i = 0; i < (int)S.size(); i++) {
        Vertex u = S[i];
        // std::cout << "find_tree_size: " << u << " " << find_tree_size(u, tree_size_, F_) << std::endl;
        if(find_tree_size(u, tree_size_, F_) >= k_ && prev_[u] == -1) {
            P.push_back(u);
        }
    }
    return std::make_pair(P, std::vector<Vertex>(W.begin(), W.end()));
}




void find_shortest_path(int s, const Graph& G) {
    int N = (int)G.size();
    double t = std::floor(std::pow(std::log2(N), 2.0 / 3.0));
    double l = std::ceil(std::log2(N) / t);
    ShortestPath shortest_path(s, G);
    std::vector<Vertex> S;
    S.push_back(s);
    auto bu = shortest_path.BMSSP(l, INF, S);
    // std::cout << "Bfinal:=" << bu.first << std::endl;
    shortest_path.print_dhat();
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int N, M, s;
    std::cin >> N >> M >> s;
    Graph G(N);
    for(int i = 0; i < M; i++) {
        int a, b; Length c;
        std::cin >> a >> b >> c;
        G[a].push_back(std::make_pair(b, c));
    }
    find_shortest_path(s, G);
    return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 40512
final_rank: 15

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <limits>
#include <map>
#include <algorithm>
#include <cassert>

using Vertex = int;
using Length = long long;
const Length INF = std::numeric_limits<long long>::max();
using Edge = std::pair<Vertex, Length>;
using Graph = std::vector<std::vector<Edge>>;

class BlockHeap {
    public:
        BlockHeap(int M, Length B);
        void insert(Vertex v, Length l);
        void batch_prepend(const std::vector<std::pair<Vertex, Length>>& L);
        std::pair<Length ,std::vector<Vertex>> pull();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        // We implement a buffered block-heap: new inserts go to an append buffer (buffer_),
        // batch_prepend items go to a prepend buffer (prepend_), and we maintain a small
        // active sorted set (active_) from which we pop up to M elements per pull.
        // We keep a map d_ of current best distances for vertices; entries in buffers
        // may be stale and are validated against d_ on extraction.

        std::unordered_map<Vertex, Length> d_;
        std::vector<std::pair<Length, Vertex>> buffer_; // append-only buffer (length, vertex)
        std::vector<std::pair<Length, Vertex>> prepend_; // items to prioritize
        std::set<std::pair<Length, Vertex>> active_; // sorted active set
        Length buffer_min_ = INF;
        Length prepend_min_ = INF;
};

BlockHeap::BlockHeap(int M, Length B) {
    M_ = M;
    B_ = B;
}

std::pair<Length, std::vector<Vertex>> BlockHeap::pull() {
    std::vector<Vertex> S;

    // Ensure active_ has elements to pop, preferring prepend_ then buffer_.
    if(active_.empty()) {
        // Move all prepend_ items into active_
        if(!prepend_.empty()) {
            for(auto &p : prepend_) {
                Length l = p.first; Vertex v = p.second;
                // only insert if this entry is current
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }
            prepend_.clear();
            prepend_min_ = INF;
        }
        // If still empty, move up to M_ smallest from buffer_
        if(active_.empty() && !buffer_.empty()) {
            int take = std::min((int)buffer_.size(), M_);
            // partial sort: nth_element to partition smallest 'take' elements
            std::nth_element(buffer_.begin(), buffer_.begin() + take, buffer_.end(),
                [](const std::pair<Length, Vertex>& a, const std::pair<Length, Vertex>& b){
                    return a.first < b.first;
                });
            // move the first 'take' items into active_
            for(int i = 0; i < take; ++i) {
                Length l = buffer_[i].first; Vertex v = buffer_[i].second;
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }
            // rebuild buffer_ with remaining items
            std::vector<std::pair<Length, Vertex>> newbuf;
            newbuf.reserve(buffer_.size() - take);
            for(size_t i = take; i < buffer_.size(); ++i) newbuf.push_back(buffer_[i]);
            buffer_.swap(newbuf);
            // recompute buffer_min_
            buffer_min_ = INF;
            for(auto &p : buffer_) buffer_min_ = std::min(buffer_min_, p.first);
        }
    }

    // Pop up to M_ items from active_
    for(int i = 0; i < M_; ++i) {
        if(active_.empty()) break;
        auto p = *active_.begin();
        active_.erase(active_.begin());
        Vertex v = p.second; Length l = p.first;
        auto it = d_.find(v);
        if(it != d_.end() && it->second == l) {
            // valid
            S.push_back(v);
            d_.erase(it);
        }
        // otherwise stale, skip
    }

    // compute next threshold Bi
    Length next_min = INF;
    if(!active_.empty()) next_min = std::min(next_min, active_.begin()->first);
    if(buffer_min_ < next_min) next_min = buffer_min_;
    if(prepend_min_ < next_min) next_min = prepend_min_;
    if(next_min == INF) return std::make_pair(B_, S);
    return std::make_pair(next_min, S);
}

void BlockHeap::batch_prepend(const std::vector<std::pair<Vertex, Length>>& L) {
    // batch prepend: add items to prepend_ (higher priority than buffer_)
    for(const auto &p : L) {
        Vertex v = p.first; Length l = p.second;
        auto it = d_.find(v);
        if(it != d_.end()) {
            if(it->second <= l) continue;
            // update to better value
            it->second = l;
        } else {
            d_[v] = l;
        }
        prepend_.push_back(std::make_pair(l, v));
        if(l < prepend_min_) prepend_min_ = l;
    }
}

void BlockHeap::insert(Vertex v, Length l) {
    auto it = d_.find(v);
    if(it != d_.end()) {
        if(it->second <= l) return; // no improvement
        it->second = l;
    } else {
        d_[v] = l;
    }
    buffer_.push_back(std::make_pair(l, v));
    if(l < buffer_min_) buffer_min_ = l;
}

bool BlockHeap::empty() {
    return d_.empty();
}

void BlockHeap::debug() {
    std::cout << "D(active)= [";
    for(auto p: active_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(prepend)= [";
    for(auto &p: prepend_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(buffer)= [";
    for(auto &p: buffer_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class Heap {
    public:
        void push(Vertex v, Length l);
        std::pair<Vertex, Length> top();
        void pop();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        std::set<std::pair<Length, Vertex>> que_;
        std::unordered_map<Vertex, Length> d_;

};

void Heap::push(Vertex v, Length l) {
    if(d_.count(v) != 0 && d_[v] < l) {
        return;
    } else if (d_.count(v) != 0 && d_[v] >= l) {
        que_.erase(std::make_pair(d_[v], v));
    }
    que_.insert(std::make_pair(l, v));
    d_[v] = l;
}

std::pair<Vertex, Length> Heap::top() {
    auto p = *que_.begin();
    return std::make_pair(p.second, p.first);
}

void Heap::pop() {
    auto t = top();
    Vertex v = t.first;
    d_.erase(v);
    que_.erase(que_.begin());
}

bool Heap::empty() {
    return que_.empty();
}

void Heap::debug() {
    std::cout << "H= [";
    for(auto p: que_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class ShortestPath {
    public:
        ShortestPath(Vertex s, const Graph& G);
        std::pair<Length, std::vector<Vertex>> BMSSP(int l, Length B, const std::vector<Vertex>& S);
        std::pair<std::vector<Vertex>, std::vector<Vertex>> find_pivots(Length B, const std::vector<Vertex>& S);
        void print_dhat();

    private:
        int t_;
        int k_;
        std::vector<Length> dhat_;
        Graph G_;

        std::pair<Length, std::vector<Vertex>> base_case(Length B, const std::vector<Vertex>& S);

        std::vector<Vertex> prev_;
        std::vector<int> tree_size_;
        std::vector<std::vector<Vertex>> F_;
};

ShortestPath::ShortestPath(Vertex s, const Graph& G) {
    G_ = G;
    int N = G_.size();
    k_ = std::ceil(pow(std::log2(N), 1.0 / 3.0));
    t_ = std::floor(pow(std::log2(N), 2.0 / 3.0));
    dhat_ = std::vector<Length>(N, INF);
    dhat_[s] = 0;
    prev_ = std::vector<Vertex>(N, -1);
    tree_size_ = std::vector<Vertex>(N, -1);
    F_ = std::vector<std::vector<Vertex>>(N, std::vector<Vertex>());
}

namespace {
    int find_tree_size(int u, std::vector<int>& tree_size, const std::vector<std::vector<Vertex>>& F) {
        if(tree_size[u] != -1) return tree_size[u];
        int res = 1;
        for(int i = 0; i < (int)F[u].size(); i++) {
            Vertex v = F[u][i];
            res += find_tree_size(v, tree_size, F);
        }
        return tree_size[u] = res;
    }

    void debug_vertex_set(std::vector<Vertex> S) {
        std::cout << "[";
        for(int i = 0; i < (int)S.size(); i++) {
            std::cout << S[i] << ", ";
        }
        std::cout << "]" << std::endl;
    }
}

void ShortestPath::print_dhat() {
    for(int i = 0; i < (int)dhat_.size(); i++) {
        if(dhat_[i] == INF) {
            std::cout << "INF" << std::endl;
        } else {
            std::cout << dhat_[i] << std::endl;
        }
    }
    // std::cout << "[";
    // for(int i = 0; i < (int)dhat_.size(); i++) {
    //     if(dhat_[i] == INF) {
    //         std::cout << "INF" << ", ";
    //     } else {
    //         std::cout << dhat_[i] << ", ";
    //     }
    // }
    // std::cout << "]" << std::endl;
}

std::pair<Length, std::vector<Vertex>> ShortestPath::BMSSP(int l, Length B, const std::vector<Vertex>& S) {
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", S=";
    // debug_vertex_set(S);
    // print_dhat();
    if(l == 0) {
        return base_case(B, S);
    }
    auto pw = find_pivots(B, S);
    std::vector<Vertex> P = pw.first; std::vector<Vertex> W = pw.second;
    // std::cout << "P= "; debug_vertex_set(P);
    // std::cout << "W= "; debug_vertex_set(W);

    int M = std::pow(2, (l - 1) * t_);
    BlockHeap D(M, B);
    Length Bd = INF;
    for(int i = 0; i < (int)P.size(); i++) {
        Vertex u = P[i];
        D.insert(u, dhat_[u]);
        Bd = std::min(Bd, dhat_[u]);
    }
    // D.debug();
    std::unordered_set<Vertex> U;

    while((int)U.size() < k_ * std::pow(2, l * t_) && !D.empty()) {
        auto bs = D.pull();
        Length Bi = bs.first; std::vector<Vertex> Si = bs.second;
        if (Si.empty()) {
            continue; 
        }
        
        auto bu = BMSSP(l - 1, Bi, Si);
        Length Bid = bu.first; std::vector<Vertex> Ui = bu.second;
        // std::cout << "Bid=" << Bid << std::endl;
        // std::cout << "Ui="; debug_vertex_set(Ui);
        // std::cout << "U="; debug_vertex_set(std::vector<Vertex>(U.begin(), U.end()));
        for(int j = 0; j < (int)Ui.size(); j++) {
            // if(U.count(Ui[j]) != 0) {
            //     std::cout << "Ufound" << " " << Ui[j] << " " << dhat_[Ui[j]] << " " << Bi << " " << Bid << std::endl;
            // }
            U.insert(Ui[j]);
        }

        std::vector<std::pair<Vertex, Length>> K;
        for(int j = 0; j < (int)Ui.size(); j++) {
            Vertex u = Ui[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    Length new_dist = dhat_[u] + w;
                    dhat_[v] = new_dist;
                    if(Bi <= new_dist && new_dist < B) {
                        D.insert(v, new_dist);
                    } else if(Bid <= new_dist && new_dist < Bi) {
                        K.push_back(std::make_pair(v, new_dist));
                    }
                }
            }
        }
        for(int i = 0; i < (int)Si.size(); i++) {
            int u = Si[i];
            if(Bid <= dhat_[u] && dhat_[u] < Bi) K.push_back(std::make_pair(u, dhat_[u]));
        }
        D.batch_prepend(K);
        Bd = Bid;
    }
    Bd = std::min(Bd, B);
    for(int i = 0; i < (int)W.size(); i++) {
        Vertex u = W[i];
        if(dhat_[u] < Bd) U.insert(u);
    }
    if(l == 3) {
        for(int i = 0; i < (int)G_.size(); i++) {
            // if(!U.count(i) && dhat_[i] != INF) {
            //     std::cout << "found: " << i << " " << dhat_[i] << std::endl;
            // }
        }
    }
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", Bd=" << Bd << std::endl;
    // std::cout << "U size:=" << U.size() << " " << (D.empty() ? "empty" : "notempty") << std::endl;
    return std::make_pair(Bd, std::vector<Vertex>(U.begin(), U.end()));
}

std::pair<Length, std::vector<Vertex>> ShortestPath::base_case(Length B, const std::vector<Vertex>& S) {
    assert(S.size() == 1);

    Vertex x = S[0];
    // std::cout << "base_case k=" << k_ << ", t=" << t_ << ", B=" << B << ", x=" << x << std::endl; 

    std::unordered_set<Vertex> U0(S.begin(), S.end());
    Heap H;
    H.push(x, dhat_[x]);

    while(!H.empty() && (int)U0.size() < k_ + 1) {
        auto p = H.top(); H.pop();
        Vertex u = p.first; Length d = p.second;
        U0.insert(u);

        for(int i = 0; i < (int)G_[u].size(); i++) {
            int v = G_[u][i].first; Length w = G_[u][i].second;
            if(dhat_[v] >= dhat_[u] + w && dhat_[u] + w < B) {
                dhat_[v] = dhat_[u] + w;
                H.push(v, dhat_[v]);
            }
        }
        // H.debug();
    }

    if((int)U0.size() <= k_) {
        return make_pair(B, std::vector<Vertex>(U0.begin(), U0.end()));
    } else {
        Length Bd = -INF;
        std::vector<Vertex> U;
        for(auto u: U0) {
            Bd = std::max(Bd, dhat_[u]);
        }
        for(auto u: U0) {
            if(dhat_[u] < Bd) {
                U.push_back(u);
            }
        }
        return make_pair(Bd, U);
    }
}


std::pair<std::vector<Vertex>, std::vector<Vertex>> ShortestPath::find_pivots(Length B, const std::vector<Vertex>& S) {
    std::unordered_set<Vertex> W(S.begin(), S.end());
    std::vector<Vertex> Wp = S;

    for(auto v: W) {
        prev_[v] = -1;
    }

    for(int i = 0; i < k_; i++) {
        std::vector<Vertex> Wi; 
        for(int j = 0; j < (int)Wp.size(); j++) {
            Vertex u = Wp[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    dhat_[v] = dhat_[u] + w;
                    prev_[v] = u;
                    // if(dhat_[u] + w < B) {
                        Wi.push_back(v);
                    // }
                }
            }
        }
        for(int k = 0; k < (int)Wi.size(); k++) {
            W.insert(Wi[k]);
        }
        if((int)W.size() >= k_ * (int)S.size()) {
            return std::make_pair(S, std::vector<Vertex>(W.begin(), W.end()));
        }
        Wp = Wi;
        // std::cout << "Wp ="; debug_vertex_set(Wp);
    }

    for(auto v: W) {
        tree_size_[v] = -1;
        F_[v].clear();
    }
    for(auto v: W) {
        Vertex u = prev_[v];
        if(u == -1) continue;
        F_[u].push_back(v);
    }
    std::vector<Vertex> P;
    for(int i = 0; i < (int)S.size(); i++) {
        Vertex u = S[i];
        // std::cout << "find_tree_size: " << u << " " << find_tree_size(u, tree_size_, F_) << std::endl;
        if(find_tree_size(u, tree_size_, F_) >= k_ && prev_[u] == -1) {
            P.push_back(u);
        }
    }
    return std::make_pair(P, std::vector<Vertex>(W.begin(), W.end()));
}




void find_shortest_path(int s, const Graph& G) {
    int N = (int)G.size();
    double t = std::floor(std::pow(std::log2(N), 2.0 / 3.0));
    double l = std::ceil(std::log2(N) / t);
    ShortestPath shortest_path(s, G);
    std::vector<Vertex> S;
    S.push_back(s);
    auto bu = shortest_path.BMSSP(l, INF, S);
    // std::cout << "Bfinal:=" << bu.first << std::endl;
    shortest_path.print_dhat();
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int N, M, s;
    std::cin >> N >> M >> s;
    Graph G(N);
    for(int i = 0; i < M; i++) {
        int a, b; Length c;
        std::cin >> a >> b >> c;
        G[a].push_back(std::make_pair(b, c));
    }
    find_shortest_path(s, G);
    return 0;
}
accuracy: 1
time_ms: 380
memory_kb: 40596
final_rank: 17

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <limits>
#include <map>
#include <algorithm>
#include <cassert>

using Vertex = int;
using Length = long long;
const Length INF = std::numeric_limits<long long>::max();
using Edge = std::pair<Vertex, Length>;
using Graph = std::vector<std::vector<Edge>>;

class BlockHeap {
    public:
        BlockHeap(int M, Length B);
        void insert(Vertex v, Length l);
        void batch_prepend(const std::vector<std::pair<Vertex, Length>>& L);
        std::pair<Length ,std::vector<Vertex>> pull();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        // We implement a buffered block-heap: new inserts go to an append buffer (buffer_),
        // batch_prepend items go to a prepend buffer (prepend_), and we maintain a small
        // active sorted set (active_) from which we pop up to M elements per pull.
        // We keep a map d_ of current best distances for vertices; entries in buffers
        // may be stale and are validated against d_ on extraction.

        std::unordered_map<Vertex, Length> d_;
        std::vector<std::pair<Length, Vertex>> buffer_; // append-only buffer (length, vertex)
        std::vector<std::pair<Length, Vertex>> prepend_; // items to prioritize
        std::set<std::pair<Length, Vertex>> active_; // sorted active set
        Length buffer_min_ = INF;
        Length prepend_min_ = INF;
};

BlockHeap::BlockHeap(int M, Length B) {
    M_ = M;
    B_ = B;
}

std::pair<Length, std::vector<Vertex>> BlockHeap::pull() {
    std::vector<Vertex> S;

    // Ensure active_ has elements to pop, preferring prepend_ then buffer_.
    if(active_.empty()) {
        // Move all prepend_ items into active_
        if(!prepend_.empty()) {
            for(auto &p : prepend_) {
                Length l = p.first; Vertex v = p.second;
                // only insert if this entry is current
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }
            prepend_.clear();
            prepend_min_ = INF;
        }
        // If still empty, move up to M_ smallest from buffer_
        if(active_.empty() && !buffer_.empty()) {
            int take = std::min((int)buffer_.size(), M_);
            // partial sort: nth_element to partition smallest 'take' elements
            std::nth_element(buffer_.begin(), buffer_.begin() + take, buffer_.end(),
                [](const std::pair<Length, Vertex>& a, const std::pair<Length, Vertex>& b){
                    return a.first < b.first;
                });
            // move the first 'take' items into active_
            for(int i = 0; i < take; ++i) {
                Length l = buffer_[i].first; Vertex v = buffer_[i].second;
                auto it = d_.find(v);
                if(it != d_.end() && it->second == l) {
                    active_.insert(std::make_pair(l, v));
                }
            }
            // rebuild buffer_ with remaining items
            std::vector<std::pair<Length, Vertex>> newbuf;
            newbuf.reserve(buffer_.size() - take);
            for(size_t i = take; i < buffer_.size(); ++i) newbuf.push_back(buffer_[i]);
            buffer_.swap(newbuf);
            // recompute buffer_min_
            buffer_min_ = INF;
            for(auto &p : buffer_) buffer_min_ = std::min(buffer_min_, p.first);
        }
    }

    // Pop up to M_ items from active_
    for(int i = 0; i < M_; ++i) {
        if(active_.empty()) break;
        auto p = *active_.begin();
        active_.erase(active_.begin());
        Vertex v = p.second; Length l = p.first;
        auto it = d_.find(v);
        if(it != d_.end() && it->second == l) {
            // valid
            S.push_back(v);
            d_.erase(it);
        }
        // otherwise stale, skip
    }

    // compute next threshold Bi
    Length next_min = INF;
    if(!active_.empty()) next_min = std::min(next_min, active_.begin()->first);
    if(buffer_min_ < next_min) next_min = buffer_min_;
    if(prepend_min_ < next_min) next_min = prepend_min_;
    if(next_min == INF) return std::make_pair(B_, S);
    return std::make_pair(next_min, S);
}

void BlockHeap::batch_prepend(const std::vector<std::pair<Vertex, Length>>& L) {
    // batch prepend: add items to prepend_ (higher priority than buffer_)
    for(const auto &p : L) {
        Vertex v = p.first; Length l = p.second;
        auto it = d_.find(v);
        if(it != d_.end()) {
            if(it->second <= l) continue;
            // update to better value
            it->second = l;
        } else {
            d_[v] = l;
        }
        prepend_.push_back(std::make_pair(l, v));
        if(l < prepend_min_) prepend_min_ = l;
    }
}

void BlockHeap::insert(Vertex v, Length l) {
    auto it = d_.find(v);
    if(it != d_.end()) {
        if(it->second <= l) return; // no improvement
        it->second = l;
    } else {
        d_[v] = l;
    }
    buffer_.push_back(std::make_pair(l, v));
    if(l < buffer_min_) buffer_min_ = l;
}

bool BlockHeap::empty() {
    return d_.empty();
}

void BlockHeap::debug() {
    std::cout << "D(active)= [";
    for(auto p: active_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(prepend)= [";
    for(auto &p: prepend_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(buffer)= [";
    for(auto &p: buffer_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class Heap {
    public:
        void push(Vertex v, Length l);
        std::pair<Vertex, Length> top();
        void pop();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        std::set<std::pair<Length, Vertex>> que_;
        std::unordered_map<Vertex, Length> d_;

};

void Heap::push(Vertex v, Length l) {
    if(d_.count(v) != 0 && d_[v] < l) {
        return;
    } else if (d_.count(v) != 0 && d_[v] >= l) {
        que_.erase(std::make_pair(d_[v], v));
    }
    que_.insert(std::make_pair(l, v));
    d_[v] = l;
}

std::pair<Vertex, Length> Heap::top() {
    auto p = *que_.begin();
    return std::make_pair(p.second, p.first);
}

void Heap::pop() {
    d_.erase(top().second);
    que_.erase(que_.begin());
}

bool Heap::empty() {
    return que_.empty();
}

void Heap::debug() {
    std::cout << "H= [";
    for(auto p: que_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class ShortestPath {
    public:
        ShortestPath(Vertex s, const Graph& G);
        std::pair<Length, std::vector<Vertex>> BMSSP(int l, Length B, const std::vector<Vertex>& S);
        std::pair<std::vector<Vertex>, std::vector<Vertex>> find_pivots(Length B, const std::vector<Vertex>& S);
        void print_dhat();

    private:
        int t_;
        int k_;
        std::vector<Length> dhat_;
        Graph G_;

        std::pair<Length, std::vector<Vertex>> base_case(Length B, const std::vector<Vertex>& S);

        std::vector<Vertex> prev_;
        std::vector<int> tree_size_;
        std::vector<std::vector<Vertex>> F_;
};

ShortestPath::ShortestPath(Vertex s, const Graph& G) {
    G_ = G;
    int N = G_.size();
    k_ = std::ceil(pow(std::log2(N), 1.0 / 3.0));
    t_ = std::floor(pow(std::log2(N), 2.0 / 3.0));
    dhat_ = std::vector<Length>(N, INF);
    dhat_[s] = 0;
    prev_ = std::vector<Vertex>(N, -1);
    tree_size_ = std::vector<Vertex>(N, -1);
    F_ = std::vector<std::vector<Vertex>>(N, std::vector<Vertex>());
}

namespace {
    int find_tree_size(int u, std::vector<int>& tree_size, const std::vector<std::vector<Vertex>>& F) {
        if(tree_size[u] != -1) return tree_size[u];
        int res = 1;
        for(int i = 0; i < (int)F[u].size(); i++) {
            Vertex v = F[u][i];
            res += find_tree_size(v, tree_size, F);
        }
        return tree_size[u] = res;
    }

    void debug_vertex_set(std::vector<Vertex> S) {
        std::cout << "[";
        for(int i = 0; i < (int)S.size(); i++) {
            std::cout << S[i] << ", ";
        }
        std::cout << "]" << std::endl;
    }
}

void ShortestPath::print_dhat() {
    for(int i = 0; i < (int)dhat_.size(); i++) {
        if(dhat_[i] == INF) {
            std::cout << "INF" << std::endl;
        } else {
            std::cout << dhat_[i] << std::endl;
        }
    }
    // std::cout << "[";
    // for(int i = 0; i < (int)dhat_.size(); i++) {
    //     if(dhat_[i] == INF) {
    //         std::cout << "INF" << ", ";
    //     } else {
    //         std::cout << dhat_[i] << ", ";
    //     }
    // }
    // std::cout << "]" << std::endl;
}

std::pair<Length, std::vector<Vertex>> ShortestPath::BMSSP(int l, Length B, const std::vector<Vertex>& S) {
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", S=";
    // debug_vertex_set(S);
    // print_dhat();
    if(l == 0) {
        return base_case(B, S);
    }
    auto pw = find_pivots(B, S);
    std::vector<Vertex> P = pw.first; std::vector<Vertex> W = pw.second;
    // std::cout << "P= "; debug_vertex_set(P);
    // std::cout << "W= "; debug_vertex_set(W);

    int M = std::pow(2, (l - 1) * t_);
    BlockHeap D(M, B);
    Length Bd = INF;
    for(int i = 0; i < (int)P.size(); i++) {
        Vertex u = P[i];
        D.insert(u, dhat_[u]);
        Bd = std::min(Bd, dhat_[u]);
    }
    // D.debug();
    std::unordered_set<Vertex> U;

    while((int)U.size() < k_ * std::pow(2, l * t_) && !D.empty()) {
        auto bs = D.pull();
        Length Bi = bs.first; std::vector<Vertex> Si = bs.second;
        if (Si.empty()) {
            continue; 
        }
        
        auto bu = BMSSP(l - 1, Bi, Si);
        Length Bid = bu.first; std::vector<Vertex> Ui = bu.second;
        // std::cout << "Bid=" << Bid << std::endl;
        // std::cout << "Ui="; debug_vertex_set(Ui);
        // std::cout << "U="; debug_vertex_set(std::vector<Vertex>(U.begin(), U.end()));
        for(int j = 0; j < (int)Ui.size(); j++) {
            // if(U.count(Ui[j]) != 0) {
            //     std::cout << "Ufound" << " " << Ui[j] << " " << dhat_[Ui[j]] << " " << Bi << " " << Bid << std::endl;
            // }
            U.insert(Ui[j]);
        }

        std::vector<std::pair<Vertex, Length>> K;
        for(int j = 0; j < (int)Ui.size(); j++) {
            Vertex u = Ui[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    Length new_dist = dhat_[u] + w;
                    dhat_[v] = new_dist;
                    if(Bi <= new_dist && new_dist < B) {
                        D.insert(v, new_dist);
                    } else if(Bid <= new_dist && new_dist < Bi) {
                        K.push_back(std::make_pair(v, new_dist));
                    }
                }
            }
        }
        for(int i = 0; i < (int)Si.size(); i++) {
            int u = Si[i];
            if(Bid <= dhat_[u] && dhat_[u] < Bi) K.push_back(std::make_pair(u, dhat_[u]));
        }
        D.batch_prepend(K);
        Bd = Bid;
    }
    Bd = std::min(Bd, B);
    for(int i = 0; i < (int)W.size(); i++) {
        Vertex u = W[i];
        if(dhat_[u] < Bd) U.insert(u);
    }
    if(l == 3) {
        for(int i = 0; i < (int)G_.size(); i++) {
            // if(!U.count(i) && dhat_[i] != INF) {
            //     std::cout << "found: " << i << " " << dhat_[i] << std::endl;
            // }
        }
    }
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", Bd=" << Bd << std::endl;
    // std::cout << "U size:=" << U.size() << " " << (D.empty() ? "empty" : "notempty") << std::endl;
    return std::make_pair(Bd, std::vector<Vertex>(U.begin(), U.end()));
}

std::pair<Length, std::vector<Vertex>> ShortestPath::base_case(Length B, const std::vector<Vertex>& S) {
    assert(S.size() == 1);

    Vertex x = S[0];
    // std::cout << "base_case k=" << k_ << ", t=" << t_ << ", B=" << B << ", x=" << x << std::endl; 

    std::unordered_set<Vertex> U0(S.begin(), S.end());
    Heap H;
    H.push(x, dhat_[x]);

    while(!H.empty() && (int)U0.size() < k_ + 1) {
        auto p = H.top(); H.pop();
        Vertex u = p.first; Length d = p.second;
        U0.insert(u);

        for(int i = 0; i < (int)G_[u].size(); i++) {
            int v = G_[u][i].first; Length w = G_[u][i].second;
            if(dhat_[v] >= dhat_[u] + w && dhat_[u] + w < B) {
                dhat_[v] = dhat_[u] + w;
                H.push(v, dhat_[v]);
            }
        }
        // H.debug();
    }

    if((int)U0.size() <= k_) {
        return make_pair(B, std::vector<Vertex>(U0.begin(), U0.end()));
    } else {
        Length Bd = -INF;
        std::vector<Vertex> U;
        for(auto u: U0) {
            Bd = std::max(Bd, dhat_[u]);
        }
        for(auto u: U0) {
            if(dhat_[u] < Bd) {
                U.push_back(u);
            }
        }
        return make_pair(Bd, U);
    }
}


std::pair<std::vector<Vertex>, std::vector<Vertex>> ShortestPath::find_pivots(Length B, const std::vector<Vertex>& S) {
    std::unordered_set<Vertex> W(S.begin(), S.end());
    std::vector<Vertex> Wp = S;

    for(auto v: W) {
        prev_[v] = -1;
    }

    for(int i = 0; i < k_; i++) {
        std::vector<Vertex> Wi; 
        for(int j = 0; j < (int)Wp.size(); j++) {
            Vertex u = Wp[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    dhat_[v] = dhat_[u] + w;
                    prev_[v] = u;
                    // if(dhat_[u] + w < B) {
                        Wi.push_back(v);
                    // }
                }
            }
        }
        for(int k = 0; k < (int)Wi.size(); k++) {
            W.insert(Wi[k]);
        }
        if((int)W.size() >= k_ * (int)S.size()) {
            return std::make_pair(S, std::vector<Vertex>(W.begin(), W.end()));
        }
        Wp = Wi;
        // std::cout << "Wp ="; debug_vertex_set(Wp);
    }

    for(auto v: W) {
        tree_size_[v] = -1;
        F_[v].clear();
    }
    for(auto v: W) {
        Vertex u = prev_[v];
        if(u == -1) continue;
        F_[u].push_back(v);
    }
    std::vector<Vertex> P;
    for(int i = 0; i < (int)S.size(); i++) {
        Vertex u = S[i];
        // std::cout << "find_tree_size: " << u << " " << find_tree_size(u, tree_size_, F_) << std::endl;
        if(find_tree_size(u, tree_size_, F_) >= k_ && prev_[u] == -1) {
            P.push_back(u);
        }
    }
    return std::make_pair(P, std::vector<Vertex>(W.begin(), W.end()));
}




void find_shortest_path(int s, const Graph& G) {
    int N = (int)G.size();
    double t = std::floor(std::pow(std::log2(N), 2.0 / 3.0));
    double l = std::ceil(std::log2(N) / t);
    ShortestPath shortest_path(s, G);
    std::vector<Vertex> S;
    S.push_back(s);
    auto bu = shortest_path.BMSSP(l, INF, S);
    // std::cout << "Bfinal:=" << bu.first << std::endl;
    shortest_path.print_dhat();
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int N, M, s;
    std::cin >> N >> M >> s;
    Graph G(N);
    for(int i = 0; i < M; i++) {
        int a, b; Length c;
        std::cin >> a >> b >> c;
        G[a].push_back(std::make_pair(b, c));
    }
    find_shortest_path(s, G);
    return 0;
}
accuracy: 1
time_ms: 380
memory_kb: 40532
final_rank: 16

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <limits>
#include <map>
#include <algorithm>
#include <cassert>

using Vertex = int;
using Length = long long;
const Length INF = std::numeric_limits<long long>::max();
using Edge = std::pair<Vertex, Length>;
using Graph = std::vector<std::vector<Edge>>;

class BlockHeap {
    public:
        BlockHeap(int M, Length B);
        void insert(Vertex v, Length l);
        void batch_prepend(const std::vector<std::pair<Vertex, Length>>& L);
        std::pair<Length ,std::vector<Vertex>> pull();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        // We implement a buffered block-heap: new inserts go to an append buffer (buffer_),
        // batch_prepend items go to a prepend buffer (prepend_), and we maintain a small
        // active sorted set (active_) from which we pop up to M elements per pull.
        // We keep a map d_ of current best distances for vertices; entries in buffers
        // may be stale and are validated against d_ on extraction.

        std::unordered_map<Vertex, Length> d_;
        std::vector<std::pair<Length, Vertex>> buffer_; // append-only buffer (length, vertex)
        std::vector<std::pair<Length, Vertex>> prepend_; // items to prioritize
        std::set<std::pair<Length, Vertex>> active_; // sorted active set
        Length buffer_min_ = INF;
        Length prepend_min_ = INF;
};

BlockHeap::BlockHeap(int M, Length B) {
    M_ = M;
    B_ = B;
}

std::pair<Length, std::vector<Vertex>> BlockHeap::pull() {
    std::vector<Vertex> S;
    // debug trace disabled

    // Ensure active_ has elements to pop, preferring prepend_ then buffer_.
    if(active_.empty()) {
        // Move all prepend_ items into active_
        if(!prepend_.empty()) {
            // Use current d_ values for prepend_ entries and deduplicate by vertex
            for(auto &p : prepend_) {
                Vertex v = p.second;
                auto it = d_.find(v);
                if(it != d_.end()) {
                    active_.insert(std::make_pair(it->second, v));
                }
            }
            prepend_.clear();
            prepend_min_ = INF;
        }
        // If still empty, move up to M_ smallest from buffer_
        if(active_.empty() && !buffer_.empty()) {
            // Collapse buffer_ by vertex to current d_ values to avoid stale entries
            std::unordered_map<Vertex, Length> cur;
            cur.reserve(buffer_.size()*2);
            for(auto &p : buffer_) {
                Vertex v = p.second;
                auto it = d_.find(v);
                if(it != d_.end()) cur[v] = it->second;
            }
            std::vector<std::pair<Length, Vertex>> candidates;
            candidates.reserve(cur.size());
            for(auto &kv : cur) candidates.emplace_back(kv.second, kv.first);
            int take = std::min((int)candidates.size(), M_);
            // If take equals full buffer size, move all items; otherwise use nth_element
            if(take >= (int)candidates.size()) {
                for(auto &c : candidates) active_.insert(c);
                // all candidates moved
                buffer_.clear();
            } else {
                std::nth_element(candidates.begin(), candidates.begin() + take, candidates.end(),
                    [](const std::pair<Length, Vertex>& a, const std::pair<Length, Vertex>& b){
                        return a.first < b.first;
                    });
                std::unordered_set<Vertex> moved;
                moved.reserve(take*2 + 1);
                for(int i = 0; i < take; ++i) {
                    active_.insert(candidates[i]);
                    moved.insert(candidates[i].second);
                }
                // rebuild buffer_ from remaining candidates (store current values)
                std::vector<std::pair<Length, Vertex>> newbuf;
                newbuf.reserve(candidates.size() - take);
                for(auto &c : candidates) {
                    if(moved.count(c.second) == 0) newbuf.push_back(c);
                }
                buffer_.swap(newbuf);
            }
            // recompute buffer_min_
            buffer_min_ = INF;
            for(auto &p : buffer_) buffer_min_ = std::min(buffer_min_, p.first);
        }
    }

    // Pop up to M_ items from active_
    // (internal) active_ contents debug removed
    // Pop until we collected up to M_ valid items (skip stale entries)
    while((int)S.size() < M_ && !active_.empty()) {
        auto p = *active_.begin();
        active_.erase(active_.begin());
        Vertex v = p.second; Length l = p.first;
        auto it = d_.find(v);
        if(it != d_.end() && it->second == l) {
            // valid
            S.push_back(v);
            d_.erase(it);
        }
        // otherwise stale, skip and continue popping
    }

    // compute next threshold Bi
    Length next_min = INF;
    if(!active_.empty()) next_min = std::min(next_min, active_.begin()->first);
    if(buffer_min_ < next_min) next_min = buffer_min_;
    if(prepend_min_ < next_min) next_min = prepend_min_;
    // If we didn't collect any valid items but there are still candidates in buffers,
    // pick one current-min candidate as a fallback (to avoid returning empty S when
    // the structure was considered non-empty).
    if(S.empty()) {
        Vertex pick = -1; Length pick_len = INF;
        // check active_ (their lengths may be stale, but prefer matching current d_)
        for(auto &p : active_) {
            Vertex v = p.second;
            auto it = d_.find(v);
            if(it != d_.end() && it->second < pick_len) { pick_len = it->second; pick = v; }
        }
        // check prepend_
        for(auto &p : prepend_) {
            Vertex v = p.second;
            auto it = d_.find(v);
            if(it != d_.end() && it->second < pick_len) { pick_len = it->second; pick = v; }
        }
        // check buffer_
        for(auto &p : buffer_) {
            Vertex v = p.second;
            auto it = d_.find(v);
            if(it != d_.end() && it->second < pick_len) { pick_len = it->second; pick = v; }
        }
        if(pick != -1) {
            // remove pick from data structures
            d_.erase(pick);
            // remove from active_
            for(auto it = active_.begin(); it != active_.end();) {
                if(it->second == pick) it = active_.erase(it);
                else ++it;
            }
            // remove from prepend_
            std::vector<std::pair<Length, Vertex>> np;
            for(auto &p: prepend_) if(p.second != pick) np.push_back(p);
            prepend_.swap(np);
            // remove from buffer_
            std::vector<std::pair<Length, Vertex>> nb;
            for(auto &p: buffer_) if(p.second != pick) nb.push_back(p);
            buffer_.swap(nb);
            // recompute mins
            buffer_min_ = INF; for(auto &p: buffer_) buffer_min_ = std::min(buffer_min_, p.first);
            prepend_min_ = INF; for(auto &p: prepend_) prepend_min_ = std::min(prepend_min_, p.first);
            S.push_back(pick);
        }
    }

    if(next_min == INF) return std::make_pair(B_, S);
    return std::make_pair(next_min, S);
}

void BlockHeap::batch_prepend(const std::vector<std::pair<Vertex, Length>>& L) {
    // batch prepend: add items to prepend_ (higher priority than buffer_)
    for(const auto &p : L) {
        Vertex v = p.first; Length l = p.second;
        auto it = d_.find(v);
        if(it != d_.end()) {
            if(it->second <= l) continue;
            // update to better value
            it->second = l;
        } else {
            d_[v] = l;
        }
        prepend_.push_back(std::make_pair(l, v));
        if(l < prepend_min_) prepend_min_ = l;
    }
}

void BlockHeap::insert(Vertex v, Length l) {
    auto it = d_.find(v);
    if(it != d_.end()) {
        if(it->second <= l) return; // no improvement
        it->second = l;
    } else {
        d_[v] = l;
    }
    buffer_.push_back(std::make_pair(l, v));
    if(l < buffer_min_) buffer_min_ = l;
}

bool BlockHeap::empty() {
    // Non-empty when there are any extractable (current) items in the active set or buffers.
    if(!active_.empty()) return false;
    for(auto &p: prepend_) {
        if(d_.count(p.second) != 0) return false;
    }
    for(auto &p: buffer_) {
        if(d_.count(p.second) != 0) return false;
    }
    return true;
}

void BlockHeap::debug() {
    std::cout << "D(active)= [";
    for(auto p: active_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(prepend)= [";
    for(auto &p: prepend_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]\n";
    std::cout << "D(buffer)= [";
    for(auto &p: buffer_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class Heap {
    public:
        void push(Vertex v, Length l);
        std::pair<Vertex, Length> top();
        void pop();
        bool empty();
        void debug();

    private:
        int M_;
        Length B_;

        std::set<std::pair<Length, Vertex>> que_;
        std::unordered_map<Vertex, Length> d_;

};

void Heap::push(Vertex v, Length l) {
    if(d_.count(v) != 0 && d_[v] < l) {
        return;
    } else if (d_.count(v) != 0 && d_[v] >= l) {
        que_.erase(std::make_pair(d_[v], v));
    }
    que_.insert(std::make_pair(l, v));
    d_[v] = l;
}

std::pair<Vertex, Length> Heap::top() {
    auto p = *que_.begin();
    return std::make_pair(p.second, p.first);
}

void Heap::pop() {
    d_.erase(top().second);
    que_.erase(que_.begin());
}

bool Heap::empty() {
    return que_.empty();
}

void Heap::debug() {
    std::cout << "H= [";
    for(auto p: que_) {
        std::cout << "(V=" << p.second << ", v=" << p.first << "), ";
    }
    std::cout << "]" << std::endl;
}

class ShortestPath {
    public:
        ShortestPath(Vertex s, const Graph& G);
        std::pair<Length, std::vector<Vertex>> BMSSP(int l, Length B, const std::vector<Vertex>& S);
        std::pair<std::vector<Vertex>, std::vector<Vertex>> find_pivots(Length B, const std::vector<Vertex>& S);
        void print_dhat();

    private:
        int t_;
        int k_;
        std::vector<Length> dhat_;
        Graph G_;

        std::pair<Length, std::vector<Vertex>> base_case(Length B, const std::vector<Vertex>& S);

        std::vector<Vertex> prev_;
        std::vector<int> tree_size_;
        std::vector<std::vector<Vertex>> F_;
};

ShortestPath::ShortestPath(Vertex s, const Graph& G) {
    G_ = G;
    int N = G_.size();
    k_ = std::ceil(pow(std::log2(N), 1.0 / 3.0));
    t_ = std::floor(pow(std::log2(N), 2.0 / 3.0));
    dhat_ = std::vector<Length>(N, INF);
    dhat_[s] = 0;
    prev_ = std::vector<Vertex>(N, -1);
    tree_size_ = std::vector<Vertex>(N, -1);
    F_ = std::vector<std::vector<Vertex>>(N, std::vector<Vertex>());
}

namespace {
    int find_tree_size(int u, std::vector<int>& tree_size, const std::vector<std::vector<Vertex>>& F) {
        if(tree_size[u] != -1) return tree_size[u];
        int res = 1;
        for(int i = 0; i < (int)F[u].size(); i++) {
            Vertex v = F[u][i];
            res += find_tree_size(v, tree_size, F);
        }
        return tree_size[u] = res;
    }

    void debug_vertex_set(std::vector<Vertex> S) {
        std::cout << "[";
        for(int i = 0; i < (int)S.size(); i++) {
            std::cout << S[i] << ", ";
        }
        std::cout << "]" << std::endl;
    }
}

void ShortestPath::print_dhat() {
    for(int i = 0; i < (int)dhat_.size(); i++) {
        if(dhat_[i] == INF) {
            std::cout << "INF" << std::endl;
        } else {
            std::cout << dhat_[i] << std::endl;
        }
    }
    // std::cout << "[";
    // for(int i = 0; i < (int)dhat_.size(); i++) {
    //     if(dhat_[i] == INF) {
    //         std::cout << "INF" << ", ";
    //     } else {
    //         std::cout << dhat_[i] << ", ";
    //     }
    // }
    // std::cout << "]" << std::endl;
}

std::pair<Length, std::vector<Vertex>> ShortestPath::BMSSP(int l, Length B, const std::vector<Vertex>& S) {
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", S=";
    // debug_vertex_set(S);
    // print_dhat();
    if(l == 0) {
        return base_case(B, S);
    }
    auto pw = find_pivots(B, S);
    std::vector<Vertex> P = pw.first; std::vector<Vertex> W = pw.second;
    // std::cout << "P= "; debug_vertex_set(P);
    // std::cout << "W= "; debug_vertex_set(W);

    int M = std::pow(2, (l - 1) * t_);
    BlockHeap D(M, B);
    Length Bd = INF;
    for(int i = 0; i < (int)P.size(); i++) {
        Vertex u = P[i];
        D.insert(u, dhat_[u]);
        Bd = std::min(Bd, dhat_[u]);
    }
    // D.debug();
    std::unordered_set<Vertex> U;

    while((int)U.size() < k_ * std::pow(2, l * t_) && !D.empty()) {
        auto bs = D.pull();
        Length Bi = bs.first; std::vector<Vertex> Si = bs.second;
        auto bu = BMSSP(l - 1, Bi, Si);
        Length Bid = bu.first; std::vector<Vertex> Ui = bu.second;
        // std::cout << "Bid=" << Bid << std::endl;
        // std::cout << "Ui="; debug_vertex_set(Ui);
        // std::cout << "U="; debug_vertex_set(std::vector<Vertex>(U.begin(), U.end()));
        for(int j = 0; j < (int)Ui.size(); j++) {
            // if(U.count(Ui[j]) != 0) {
            //     std::cout << "Ufound" << " " << Ui[j] << " " << dhat_[Ui[j]] << " " << Bi << " " << Bid << std::endl;
            // }
            U.insert(Ui[j]);
        }

        std::vector<std::pair<Vertex, Length>> K;
        for(int j = 0; j < (int)Ui.size(); j++) {
            Vertex u = Ui[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    Length new_dist = dhat_[u] + w;
                    dhat_[v] = new_dist;
                    if(Bi <= new_dist && new_dist < B) {
                        D.insert(v, new_dist);
                    } else if(Bid <= new_dist && new_dist < Bi) {
                        K.push_back(std::make_pair(v, new_dist));
                    }
                }
            }
        }
        for(int i = 0; i < (int)Si.size(); i++) {
            int u = Si[i];
            if(Bid <= dhat_[u] && dhat_[u] < Bi) K.push_back(std::make_pair(u, dhat_[u]));
        }
        D.batch_prepend(K);
        Bd = Bid;
    }
    Bd = std::min(Bd, B);
    for(int i = 0; i < (int)W.size(); i++) {
        Vertex u = W[i];
        if(dhat_[u] < Bd) U.insert(u);
    }
    if(l == 3) {
        for(int i = 0; i < (int)G_.size(); i++) {
            // if(!U.count(i) && dhat_[i] != INF) {
            //     std::cout << "found: " << i << " " << dhat_[i] << std::endl;
            // }
        }
    }
    // std::cout << "BMSSP k=" << k_ << ", t=" << t_ << ", l=" << l << ", B=" << B << ", Bd=" << Bd << std::endl;
    // std::cout << "U size:=" << U.size() << " " << (D.empty() ? "empty" : "notempty") << std::endl;
    return std::make_pair(Bd, std::vector<Vertex>(U.begin(), U.end()));
}

std::pair<Length, std::vector<Vertex>> ShortestPath::base_case(Length B, const std::vector<Vertex>& S) {
    assert(S.size() == 1);

    Vertex x = S[0];
    // std::cout << "base_case k=" << k_ << ", t=" << t_ << ", B=" << B << ", x=" << x << std::endl; 

    std::unordered_set<Vertex> U0(S.begin(), S.end());
    Heap H;
    H.push(x, dhat_[x]);

    while(!H.empty() && (int)U0.size() < k_ + 1) {
        auto p = H.top(); H.pop();
        Vertex u = p.first; Length d = p.second;
        U0.insert(u);

        for(int i = 0; i < (int)G_[u].size(); i++) {
            int v = G_[u][i].first; Length w = G_[u][i].second;
            if(dhat_[v] >= dhat_[u] + w && dhat_[u] + w < B) {
                dhat_[v] = dhat_[u] + w;
                H.push(v, dhat_[v]);
            }
        }
        // H.debug();
    }

    if((int)U0.size() <= k_) {
        return make_pair(B, std::vector<Vertex>(U0.begin(), U0.end()));
    } else {
        Length Bd = -INF;
        std::vector<Vertex> U;
        for(auto u: U0) {
            Bd = std::max(Bd, dhat_[u]);
        }
        for(auto u: U0) {
            if(dhat_[u] < Bd) {
                U.push_back(u);
            }
        }
        return make_pair(Bd, U);
    }
}


std::pair<std::vector<Vertex>, std::vector<Vertex>> ShortestPath::find_pivots(Length B, const std::vector<Vertex>& S) {
    std::unordered_set<Vertex> W(S.begin(), S.end());
    std::vector<Vertex> Wp = S;

    for(auto v: W) {
        prev_[v] = -1;
    }

    for(int i = 0; i < k_; i++) {
        std::vector<Vertex> Wi; 
        for(int j = 0; j < (int)Wp.size(); j++) {
            Vertex u = Wp[j];
            for(int k = 0; k < (int)G_[u].size(); k++) {
                Vertex v = G_[u][k].first; Length w = G_[u][k].second;
                if(dhat_[v] >= dhat_[u] + w) {
                    dhat_[v] = dhat_[u] + w;
                    prev_[v] = u;
                    // if(dhat_[u] + w < B) {
                        Wi.push_back(v);
                    // }
                }
            }
        }
        for(int k = 0; k < (int)Wi.size(); k++) {
            W.insert(Wi[k]);
        }
        if((int)W.size() >= k_ * (int)S.size()) {
            return std::make_pair(S, std::vector<Vertex>(W.begin(), W.end()));
        }
        Wp = Wi;
        // std::cout << "Wp ="; debug_vertex_set(Wp);
    }

    for(auto v: W) {
        tree_size_[v] = -1;
        F_[v].clear();
    }
    for(auto v: W) {
        Vertex u = prev_[v];
        if(u == -1) continue;
        F_[u].push_back(v);
    }
    std::vector<Vertex> P;
    for(int i = 0; i < (int)S.size(); i++) {
        Vertex u = S[i];
        // std::cout << "find_tree_size: " << u << " " << find_tree_size(u, tree_size_, F_) << std::endl;
        if(find_tree_size(u, tree_size_, F_) >= k_ && prev_[u] == -1) {
            P.push_back(u);
        }
    }
    return std::make_pair(P, std::vector<Vertex>(W.begin(), W.end()));
}




void find_shortest_path(int s, const Graph& G) {
    int N = (int)G.size();
    double t = std::floor(std::pow(std::log2(N), 2.0 / 3.0));
    double l = std::ceil(std::log2(N) / t);
    ShortestPath shortest_path(s, G);
    std::vector<Vertex> S;
    S.push_back(s);
    auto bu = shortest_path.BMSSP(l, INF, S);
    // std::cout << "Bfinal:=" << bu.first << std::endl;
    shortest_path.print_dhat();
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int N, M, s;
    std::cin >> N >> M >> s;
    Graph G(N);
    for(int i = 0; i < M; i++) {
        int a, b; Length c;
        std::cin >> a >> b >> c;
        G[a].push_back(std::make_pair(b, c));
    }
    find_shortest_path(s, G);
    return 0;
}
accuracy: 1
time_ms: 970
memory_kb: 41816
final_rank: 20