Problem:
Alternating path
問題
$N$ 頂点 $M$ 辺の弱連結な単純有向グラフがあります。
$i$ 番目の辺を使うと頂点 $a_i$ から $b_i$ へ移動でき、距離は $c_i$ です。
（有向辺であるため、辺 $i$ を用いて頂点 $b_i$ から $a_i$ へ移動することはできません）
通る辺の距離が増加と減少を交互に繰り返すように頂点 $1$ から頂点 $N$ まで移動したいです。
つまり、$K$ 本の辺を使用して移動するとき、 $j$ 番目に使用する辺の距離を $d_j$ とすると、
$d_j < d_{j+1}$ ならば $d_{j+1}> d_{j+2}$
$d_j > d_{j+1}$ ならば $d_{j+1} < d_{j+2}$
が $1 \leq j \leq K-2$ のすべてで成り立つ、かつ
$d_j \neq d_{j+1}$
が $1 \leq j \leq K-1$ のすべてで成り立つ必要があります。
このルールに従って頂点 $1$ から頂点 $N$ まで移動するときの合計経路長の最小値を出力してください。
不可能な場合は $-1$ を出力してください。
制約
$2 \leq N \leq 3 \times 10^5$
$1 \leq M \leq 3 \times 10^5$
$1 \leq a_i, b_i \leq N$
$a_i \neq b_i$
$i \neq j$ ならば $(a_i, b_i) \neq (a_j, b_j)$
$1 \leq c_i \leq 10^9$
与えられるグラフは弱連結である。ここで弱連結とは、辺を無向辺として見るとグラフ全体が連結になっているという意味である。
入力
$N$ $M$
$a_1$ $b_1$ $c_1$
$\vdots$
$a_M$ $b_M$ $c_M$
出力
合計経路長の最小値を出力してください。
不可能な場合は $-1$ を出力してください。
入力例 1
8 9
1 2 5
1 3 2
2 4 8
3 5 1
4 6 7
5 6 3
6 7 2
6 8 10
7 8 30
出力例 1
30
頂点 $1$ → $2$ → $4$ → $6$ → $8$ と移動すると、辺の長さが $5$, $8$, $7$, $10$ となり、合計で $30$ となります。これが最小です。
    このとき、使用する辺の距離の変化は 増加→減少→増加 となっています。
    頂点 $1$ → $3$ → $5$ → $6$ → $8$ と移動するとと合計距離が $16$ になりますが、使う辺の長さが $2$, $1$, $3$, $10$ となり、$2$
    連続で増加している部分があるので、ルールに反します。
入力例 2
5 5
1 2 1
2 3 2
4 2 3
3 4 1
3 5 4
出力例 2
13
連続で増加することを防ぐには、頂点 $1$ → $2$ → $3$ → $4$ → $2$ → $3$ → $5$ と移動しなければなりません。
入力例 3
2 1
1 2 1
出力例 3
1
入力例 4
3 2
1 2 1
2 3 2
出力例 4
3
入力例 5
3 2
1 2 1
2 3 1
出力例 5
-1
同じ距離の辺は連続して使用することは出来ません。

Submitted solutions:

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

//
// --- Custom Hash Table for Array Keys of Size M ---
// (This is your code, modified for keys of size M. We use it to mark visited states.)
//

typedef unsigned long long ull;

int gen_base(int before, int after) {
    auto seed = chrono::high_resolution_clock::now().time_since_epoch().count();
    mt19937 gen(seed ^ ull(new ull));
    uniform_int_distribution<int> dist(before+2, after-1);
    int base = dist(gen);
    return base % 2 == 0 ? base - 1 : base;
}

template <int M>
struct HashTableForArray {
    // Fixed table size; you may choose any prime (here 2000177).
    static const int mod = 2000177;
    // step is chosen randomly from [mod/10, mod)
    const int step;
    
    // Each entry stores whether it is used and the key, which is an array of M long long.
    struct Entry {
        bool used;
        array<ll, M> key;
        Entry() : used(false) {}
    };
    
    array<Entry, mod> data;
    
    HashTableForArray() : step(gen_base(mod / 10, mod)) { }
    
    inline int get_hash(const array<ll, M>& key) const {
        ull h = 0;
        for (int i = 0; i < M; i++) {
            h = h * 131ULL + (ull) key[i];
        }
        return int((h + step) % mod);
    }
    
    // Insert the key if not already present.
    void insert(const array<ll, M>& key) {
        int hash = get_hash(key);
        while (true) {
            if (!data[hash].used) {
                data[hash].used = true;
                data[hash].key = key;
                return;
            }
            if (data[hash].key == key)
                return;
            hash += step;
            if (hash >= mod) hash -= mod;
        }
    }
    
    // Search for a key. Returns true if found.
    bool search(const array<ll, M>& key) const {
        int hash = get_hash(key);
        while (true) {
            if (!data[hash].used) return false;
            if (data[hash].key == key) return true;
            hash += step;
            if (hash >= mod) hash -= mod;
        }
        return false;
    }
};

//
// --- Alternating Path Problem Solution ---
//

struct State {
    ll cost;  // total cost so far
    int v;    // current vertex
    int type; // 0: free, 1: up, 2: down
    ll last;  // weight of the last edge used
};

struct StateCompare {
    bool operator()(const State &a, const State &b) {
        return a.cost > b.cost;
    }
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int N, M;
    cin >> N >> M;
    
    // Build graph (1-indexed)
    vector<vector<pair<int, ll>>> adj(N+1);
    for (int i = 0; i < M; i++){
        int u, v;
        ll w;
        cin >> u >> v >> w;
        adj[u].push_back({v, w});
    }
    
    // Priority queue for Dijkstra’s algorithm.
    priority_queue<State, vector<State>, StateCompare> pq;
    
    // Our custom hash table will keep track of visited states.
    // We encode a state as an array: [vertex, type, last].
    HashTableForArray<3> visited;
    
    // Initialization: from vertex 1, push every outgoing edge as a "free" state.
    for (auto &edge: adj[1]) {
        int nv = edge.first;
        ll w = edge.second;
        pq.push({w, nv, 0, w});
    }
    
    ll ans = -1;
    
    while(!pq.empty()){
        State cur = pq.top();
        pq.pop();
        
        array<ll, 3> key = { (ll)cur.v, (ll)cur.type, cur.last };
        if (visited.search(key)) continue;
        visited.insert(key);
        
        // If we've reached vertex N, we found a valid alternating path.
        if (cur.v == N) {
            ans = cur.cost;
            break;
        }
        
        // Relax transitions from current state.
        for (auto &edge: adj[cur.v]) {
            int nv = edge.first;
            ll w = edge.second;
            if (cur.type == 0) {
                // In free state, the next edge must have a different weight.
                if (w == cur.last) continue;
                if (w > cur.last)
                    pq.push({cur.cost + w, nv, 2, w}); // increased: next must be lower (down state)
                else
                    pq.push({cur.cost + w, nv, 1, w}); // decreased: next must be higher (up state)
            } else if (cur.type == 1) {
                // "Up" state: previous edge was a decrease so we need w > cur.last.
                if (w > cur.last)
                    pq.push({cur.cost + w, nv, 2, w});
            } else { // cur.type == 2
                // "Down" state: previous edge was an increase so we need w < cur.last.
                if (w < cur.last)
                    pq.push({cur.cost + w, nv, 1, w});
            }
        }
    }
    
    cout << ans << "\n";
    return 0;
}
accuracy: 0.5068493150684932
time_ms: 650
memory_kb: 172044
final_rank: 17

code_snippet: #include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
vector<pair<int,int> >G[3<<17];
int L[3<<17],R[3<<17];
int N,M;
int main()
{
	cin>>N>>M;
	for(int i=0;i<M;i++)
	{
		int a,b,c;cin>>a>>b>>c;
		a--,b--;
		G[a].push_back(make_pair(c,b));
	}
	for(int i=0;i<N;i++)
	{
		sort(G[i].begin(),G[i].end());
		L[i]=0;
		R[i]=G[i].size();
	}
	priority_queue<pair<pair<long,int>,pair<int,int> > >P;
	P.push(make_pair(make_pair(0,0),make_pair(-1,1e9+1)));
	P.push(make_pair(make_pair(0,0),make_pair(1,0)));
	long ans=9e18;
	while(!P.empty())
	{
		long cost=-P.top().first.first;
		int u=P.top().first.second;
		int dir=P.top().second.first;
		int pre=P.top().second.second;
		P.pop();
		if(u==N-1)
		{
			if(ans>cost)ans=cost;
		}
		if(dir==-1)
		{
			for(;L[u]<G[u].size();L[u]++)
			{
				long ec=G[u][L[u]].first;
				if(ec>=pre)
				{
					break;
				}
				long nxt=cost+ec;
				int v=G[u][L[u]].second;
				P.push(make_pair(make_pair(-nxt,v),make_pair(1,ec)));
			}
		}
		else
		{
			for(;R[u]>0;)
			{
				R[u]--;
				long ec=G[u][R[u]].first;
				if(ec<=pre)
				{
					R[u]++;
					break;
				}
				long nxt=cost+ec;
				int v=G[u][R[u]].second;
				P.push(make_pair(make_pair(-nxt,v),make_pair(-1,ec)));
			}
		}
	}
	if(ans==(long)9e18)cout<<-1<<endl;
	else cout<<ans<<endl;
}
accuracy: 1
time_ms: 190
memory_kb: 47428
final_rank: 1

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


using namespace std;
//make -f ../makefile SRC=
/*
MLE, WA see codes

TODO
each vertex should be visited at most twice
=> dist[N][2] instead of dist[N]

5 5
1 2 1
2 3 2
4 2 3
3 4 1
3 5 4
output:
13

9 10
1 2 1
2 3 4
3 4 1
4 5 4
5 2 1
3 6 3
6 7 4
7 8 1
8 6 4
6 9 1
output:
18
5 5
1 2 1
2 3 2
4 2 3
3 4 1
3 5 4
*/


//------------------------------------------------------------------------------
bool DEBUG = false;
const int64_t INF = 1000000000000000000L;
const int BIG = 2000000000;
const int MAX_N = 300000;
const int F = 2;
static int64_t dist[MAX_N][F];

//------------------------------------------------------------------------------
struct SEdge
{
    int w, c;
    SEdge(): w(-1), c(BIG) {}
    SEdge(int v2, int cost=0): w(v2), c(cost) {}
    bool operator<(const SEdge& e1) const
    {
        return c < e1.c;
    }
    void debug() const { printf("w=%d, c=%d\n", w, c); }
};

typedef vector<SEdge> SEdges;
typedef vector<SEdges> Graph;
//------------------------------------------------------------------------------
struct Node
{
    int v, c;
    int64_t d;
    bool f;

    bool operator==(const Node& n1) const { return v == n1.v && c == n1.c && d == n1.d && f == n1.f; }
    bool operator<(const Node& n1) const
    {
        return d > n1.d; // for PQ
    }
    Node(): v(-1), c(0), d(INF), f(true) {}
    Node(int vert, int edge_cost, int64_t _dist,  bool flag): v(vert), c(edge_cost), d(_dist), f(flag) {}
};

typedef priority_queue<Node,vector<Node> > PQ;
//------------------------------------------------------------------------------
void debug_graph(int N, Graph& G)
{
    for (int v=0; v<N; v++)
        for (auto e: G[v])
            printf("%d -> %d: %d\n", v+1, e.w+1, e.c);

}

void debug_dist(int N)
{
    for (int v=0; v<N; v++)
        for (int f=0; f<F; ++f)
            if (dist[v][f] != INF)
                printf("v=%d, f=%d, dist=%ld\n", v, f, dist[v][f]);

}

bool is_incre(int N, Graph& G, int v)
{
    for (SEdge e1: G[v])
        for (SEdge e2: G[e1.w])
            if (e2.c > e1.c)
                return true;
    return false;
}

bool is_decre(int N, Graph& G, int v)
{
    for (SEdge e1: G[v])
        for (SEdge e2: G[e1.w])
            if (e2.c < e1.c)
                return true;
    return false;
}

//------------------------------------------------------------------------------
int64_t dijkstra(int N, Graph& G)
{
    int64_t res = INF;
    int src = 0;
    if (N == 2)
    {
        for (SEdge e: G[src])
            if (e.w == N-1)
                res = min(res, int64_t(e.c));
        return res;
    }
    //--------------------------------------------------------------------------
    // init:
    for (int v=0; v<N; ++v) { dist[v][0] = INF; dist[v][1] = INF; }

    PQ pq;

    if (is_incre(N, G, src))
    {
        pq.push( Node(src, BIG, 0, true) );
        dist[src][1] = 0;
    }

    if (is_decre(N, G, src))
    {
        pq.push( Node(src, -BIG, 0, false) );
        dist[src][0] = 0;
    }

    while (!pq.empty())
    {
        Node node = pq.top(); pq.pop();
        int v = node.v;
        int c = node.c;
        int64_t d = node.d;
        bool f = node.f;

        // search:
        for (SEdge e: G[v])
        {
            if (f && e.c >= c) continue;
            if (!f && e.c <= c) continue;
            if (dist[e.w][!f] == INF || dist[e.w][!f] > d + e.c)
            {
                dist[e.w][!f] = d + e.c;
                pq.push( Node(e.w, e.c, dist[e.w][!f], !f) );
            }
        }
    }
    if (DEBUG) debug_dist(N);

    if (dist[N-1][0] != INF) res = min(res, dist[N-1][0]);
    if (dist[N-1][1] != INF) res = min(res, dist[N-1][1]);
    return res;
}

//------------------------------------------------------------------------------
void test()
{

}

//------------------------------------------------------------------------------
int main()
{
    //test(); return 0;
    //DEBUG = true;
    //--------------------------------------------------------------------------
    int N, M, v, w, c, num;
    num = scanf("%d %d ", &N, &M);
    Graph G(N);
    for (int m=0; m<M; ++m)
    {
        num = scanf("%d %d %d ", &v, &w, &c);
        v--;
        w--;
        G[v].push_back(SEdge(w,c));
    }
    if (DEBUG) debug_graph(N, G);

    int64_t res = dijkstra(N, G);
    if (res == INF) printf("-1\n");
    else printf("%ld\n", res);

    //--------------------------------------------------------------------------
    return 0;
}
//------------------------------------------------------------------------------
accuracy: 0.6986301369863014
time_ms: 60
memory_kb: 24084
final_rank: 16

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


using namespace std;
//make -f ../makefile SRC=
/*
TODO

*/


//------------------------------------------------------------------------------
bool DEBUG = false;
const int64_t INF = 1000000000000000000L;
const int BIG = 2000000000;
const int MAX_N = 300000;
static int64_t dist[MAX_N];

//------------------------------------------------------------------------------
struct SEdge
{
    int w, c;
    SEdge(): w(-1), c(BIG) {}
    SEdge(int v2, int cost=0): w(v2), c(cost) {}
    bool operator<(const SEdge& e1) const
    {
        return c < e1.c;
    }
    void debug() const { printf("w=%d, c=%d\n", w, c); }
};

typedef vector<SEdge> SEdges;
typedef vector<SEdges> Graph;
//------------------------------------------------------------------------------
struct Node
{
    int v, c;
    int64_t d;
    bool f;

    bool operator==(const Node& n1) const { return v == n1.v && c == n1.c && d == n1.d && f == n1.f; }
    bool operator<(const Node& n1) const
    {
        return d > n1.d; // for PQ
    }
    Node(): v(-1), c(0), d(INF), f(true) {}
    Node(int vert, int edge_cost, int64_t _dist,  bool flag): v(vert), c(edge_cost), d(_dist), f(flag) {}
};

typedef priority_queue<Node,vector<Node> > PQ;
//------------------------------------------------------------------------------
void debug_graph(int N, Graph& G)
{
    for (int v=0; v<N; v++)
        for (auto e: G[v])
            printf("%d -> %d: %d\n", v, e.w, e.c);

}

//------------------------------------------------------------------------------
int64_t dijkstra(int N, Graph& G)
{
    //--------------------------------------------------------------------------
    // init:
    int src = 0;

    for (int v=0; v<N; ++v) dist[v] = INF;
    dist[src] = 0;

    PQ pq;
    pq.push( Node(src, BIG, 0, true) );
    pq.push( Node(src, -BIG, 0, false) );

    while (!pq.empty())
    {
        Node node = pq.top(); pq.pop();
        int v = node.v;
        if (v == N-1) return dist[v];
        int c = node.c;
        bool f = node.f;

        // search:
        for (SEdge e: G[v])
        {
            if (f && e.c >= c) continue;
            if (!f && e.c <= c) continue;
            dist[e.w] = dist[v] + e.c;
            pq.push( Node(e.w, e.c, dist[e.w], !f) );
            /*
            if (dist[e.w] == INF || dist[e.w] > dist[v] + e.c)
            {
                dist[e.w] = dist[v] + e.c;
                pq.push( Node(e.w, e.c, dist[e.w], !f) );
            }
            */
        }
    }
    if (DEBUG)
    {
        printf("dist:\n");
        for (int v=0; v<N; v++)
            if (dist[v] != INF)
                printf("v=%d, dist=%ld\n", v,  dist[v]);
    }
    return dist[N-1];
}

//------------------------------------------------------------------------------
void test()
{

}

//------------------------------------------------------------------------------
int main()
{
    //test(); return 0;
    //DEBUG = true;
    //--------------------------------------------------------------------------
    int N, M, v, w, c, num;
    num = scanf("%d %d ", &N, &M);
    Graph G(N);
    for (int m=0; m<M; ++m)
    {
        num = scanf("%d %d %d ", &v, &w, &c);
        v--;
        w--;
        G[v].push_back(SEdge(w,c));
    }
    if (DEBUG) debug_graph(N, G);

    int64_t res = dijkstra(N, G);
    if (res == INF) printf("-1\n");
    else printf("%ld\n", res);

    //--------------------------------------------------------------------------
    return 0;
}
//------------------------------------------------------------------------------
accuracy: 0.0136986301369863
time_ms: 50
memory_kb: 21916
final_rank: 20

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>

using namespace std;


int main() {
	int n, m; cin >> n >> m;
	vector<vector<int>> node(n);
	vector<pair<int, int>> edge; edge.reserve(m);
	for (auto i = 0; i < m; ++i) {
		int a, b, c; cin >> a >> b >> c; --a; --b;
		node[a].push_back(i);
		edge.emplace_back(b, c);
	}
	for (auto& n : node) sort(n.begin(), n.end(), [&edge](const int i, const int j) {return edge[i].second < edge[j].second; });
	vector<deque<int>> for0(n), for1(n);
	for (auto i = 0; i < n; ++i) {
		copy(node[i].begin(), node[i].end(), back_inserter(for0[i]));
		copy(node[i].begin(), node[i].end(), back_inserter(for1[i]));
	}
	vector<vector<long long int>> min_length(3, vector<long long int>(m, LLONG_MAX));
	const auto comparator = [](const pair<pair<int, int>, long long int>& a, const pair<pair<int, int>, long long int>& b) {return a.second > b.second; };
	priority_queue<pair<pair<int, int>, long long int>, vector<pair<pair<int, int>, long long int>>, decltype(comparator)> queue(comparator);
	for (const auto e : node[0]) {
		const auto [_, cost] = edge[e];
		min_length[2][e] = cost;
		queue.emplace(make_pair(2, e), cost);
	}
	while (!queue.empty()) {
		const auto [pair, cost] = queue.top(); queue.pop();
		//cout << cost << '\n';
		const auto [type, prev_e] = pair;
		if (min_length[type][prev_e] != cost) continue;
		const auto [from, prev] = edge[prev_e];
		if (type == 2) {
			for (const auto next_e : node[from]) {
				const auto [to, next] = edge[next_e];
				if (prev == next) continue;
				const auto next_type = prev < next ? 0 : 1;
				if (min_length[next_type][next_e] > cost + next) {
					min_length[next_type][next_e] = cost + next;
					queue.emplace(make_pair(next_type, next_e), cost + next);
				}
			}
		}
		else if (type == 1) {
			while (!for1[from].empty()) {
				const auto next_e = for1[from].back();
				const auto [to, next] = edge[next_e];
				if (next <= prev) break;
				for1[from].pop_back();
				if (min_length[1 - type][next_e] > cost + next) {
					min_length[1 - type][next_e] = cost + next;
					queue.emplace(make_pair(1 - type, next_e), cost + next);
				}
			}
		}
		else if (type == 0) {
			while (!for0[from].empty()) {
				const auto next_e = for0[from].front();
				const auto [to, next] = edge[next_e];
				if (prev <= next) break;
				for0[from].pop_front();
				if (min_length[1 - type][next_e] > cost + next) {
					min_length[1 - type][next_e] = cost + next;
					queue.emplace(make_pair(1 - type, next_e), cost + next);
				}
			}
		}
		else {
			throw 0;
		}
	}
	long long int result{ LLONG_MAX };
	for (auto i = 0; i < m; ++i) {
		if (edge[i].first == n - 1) {
			for (auto j = 0; j < 3; ++j) {
				result = min(result, min_length[j][i]);
			}
		}
	}
	if (result == LLONG_MAX) {
		cout << "-1\n";
	}
	else {
		cout << result << '\n';
	}
}
accuracy: 1
time_ms: 350
memory_kb: 434420
final_rank: 11

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>

using namespace std;


int main() {
	int n, m; cin >> n >> m;
	vector<vector<int>> node(n);
	vector<pair<int, int>> edge; edge.reserve(m);
	for (auto i = 0; i < m; ++i) {
		int a, b, c; cin >> a >> b >> c; --a; --b;
		node[a].push_back(i);
		edge.emplace_back(b, c);
	}
	for (auto& n : node) sort(n.begin(), n.end(), [&edge](const int i, const int j) {return edge[i].second < edge[j].second; });
	vector<deque<int>> sorted(n);
	for (auto i = 0; i < n; ++i) {
		copy(node[i].begin(), node[i].end(), back_inserter(sorted[i]));
	}
	vector<vector<long long int>> min_length(3, vector<long long int>(m, LLONG_MAX));
	const auto comparator = [](const pair<pair<int, int>, long long int>& a, const pair<pair<int, int>, long long int>& b) {return a.second > b.second; };
	priority_queue<pair<pair<int, int>, long long int>, vector<pair<pair<int, int>, long long int>>, decltype(comparator)> queue(comparator);
	for (const auto e : node[0]) {
		const auto [_, cost] = edge[e];
		min_length[2][e] = cost;
		queue.emplace(make_pair(2, e), cost);
	}
	while (!queue.empty()) {
		const auto [pair, cost] = queue.top(); queue.pop();
		const auto [type, prev_e] = pair;
		if (min_length[type][prev_e] != cost) continue;
		const auto [from, prev] = edge[prev_e];
		if (type == 2) {
			for (const auto next_e : node[from]) {
				const auto [to, next] = edge[next_e];
				if (prev == next) continue;
				const auto next_type = prev < next ? 0 : 1;
				if (min_length[next_type][next_e] > cost + next) {
					min_length[next_type][next_e] = cost + next;
					queue.emplace(make_pair(next_type, next_e), cost + next);
				}
			}
		}
		else if (type == 1) {
			while (!sorted[from].empty()) {
				const auto next_e = sorted[from].back();
				if (edge[next_e].second <= prev) break;
				sorted[from].pop_back();
				if (min_length[1 - type][next_e] > cost + edge[next_e].second) {
					min_length[1 - type][next_e] = cost + edge[next_e].second;
					queue.emplace(make_pair(1 - type, next_e), cost + edge[next_e].second);
				}
			}
		}
		else if (type == 0) {
			while (!sorted[from].empty()) {
				const auto next_e = sorted[from].front();
				if (prev <= edge[next_e].second) break;
				sorted[from].pop_front();
				if (min_length[1 - type][next_e] > cost + edge[next_e].second) {
					min_length[1 - type][next_e] = cost + edge[next_e].second;
					queue.emplace(make_pair(1 - type, next_e), cost + edge[next_e].second);
				}
			}
		}
		else {
			throw 0;
		}
	}
	long long int result{ LLONG_MAX };
	for (auto i = 0; i < m; ++i) {
		if (edge[i].first == n - 1) {
			for (auto j = 0; j < 3; ++j) {
				result = min(result, min_length[j][i]);
			}
		}
	}
	if (result == LLONG_MAX) {
		cout << "-1\n";
	}
	else {
		cout << result << '\n';
	}
}
accuracy: 0.1917808219178082
time_ms: 270
memory_kb: 232640
final_rank: 18

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>

using namespace std;


int main() {
	int n, m; cin >> n >> m;
	vector<vector<int>> node(n);
	vector<pair<int, int>> edge; edge.reserve(m);
	for (auto i = 0; i < m; ++i) {
		int a, b, c; cin >> a >> b >> c; --a; --b;
		node[a].push_back(i);
		edge.emplace_back(b, c);
	}
	for (auto& n : node) sort(n.begin(), n.end(), [&edge](const int i, const int j) {return edge[i].second < edge[i].second; });
	vector<deque<int>> sorted(n);
	for (auto i = 0; i < n; ++i) {
		copy(node[i].begin(), node[i].end(), back_inserter(sorted[i]));
	}
	vector<vector<long long int>> min_length(3, vector<long long int>(m, LLONG_MAX));
	const auto comparator = [](const pair<pair<int, int>, long long int>& a, const pair<pair<int, int>, long long int>& b) {return a.second > b.second; };
	priority_queue<pair<pair<int, int>, long long int>, vector<pair<pair<int, int>, long long int>>, decltype(comparator)> queue(comparator);
	for (const auto e : node[0]) {
		const auto [_, cost] = edge[e];
		min_length[2][e] = cost;
		queue.emplace(make_pair(2, e), cost);
	}
	while (!queue.empty()) {
		const auto [pair, cost] = queue.top(); queue.pop();
		const auto [type, prev_e] = pair;
		if (min_length[type][prev_e] != cost) continue;
		const auto [from, prev] = edge[prev_e];
		if (type == 2) {
			for (const auto next_e : node[from]) {
				const auto [to, next] = edge[next_e];
				if (prev == next) continue;
				const auto next_type = prev < next ? 0 : 1;
				if (min_length[next_type][next_e] > cost + next) {
					min_length[next_type][next_e] = cost + next;
					queue.emplace(make_pair(next_type, next_e), cost + next);
				}
			}
		}
		else if (type == 1) {
			while (!sorted[from].empty()) {
				const auto next_e = sorted[from].back();
				if (edge[next_e].second <= prev) break;
				sorted[from].pop_back();
				if (min_length[1 - type][next_e] > cost + edge[next_e].second) {
					min_length[1 - type][next_e] = cost + edge[next_e].second;
					queue.emplace(make_pair(1 - type, next_e), cost + edge[next_e].second);
				}
			}
		}
		else if (type == 0) {
			while (!sorted[from].empty()) {
				const auto next_e = sorted[from].front();
				if (prev <= edge[next_e].second) break;
				sorted[from].pop_front();
				if (min_length[1 - type][next_e] > cost + edge[next_e].second) {
					min_length[1 - type][next_e] = cost + edge[next_e].second;
					queue.emplace(make_pair(1 - type, next_e), cost + edge[next_e].second);
				}
			}
		}
		else {
			throw 0;
		}
	}
	long long int result{ LLONG_MAX };
	for (auto i = 0; i < m; ++i) {
		if (edge[i].first == n - 1) {
			for (auto j = 0; j < 3; ++j) {
				result = min(result, min_length[j][i]);
			}
		}
	}
	if (result == LLONG_MAX) {
		cout << "-1\n";
	}
	else {
		cout << result << '\n';
	}
}
accuracy: 0.0410958904109589
time_ms: 270
memory_kb: 232700
final_rank: 19

code_snippet: #include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#include<deque>
#include<iomanip>
#include<tuple>
#include<cassert>
#include<set>
#include<complex>
#include<numeric>
#include<functional>
using namespace std;
typedef long long int LL;
typedef pair<LL,LL> P;
typedef pair<LL,int> LP;
const LL INF=1LL<<60;
const LL MAX=1e9+7;

void array_show(int *array,int array_n,char middle=' '){
    for(int i=0;i<array_n;i++)printf("%d%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(LL *array,int array_n,char middle=' '){
    for(int i=0;i<array_n;i++)printf("%lld%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(vector<int> &vec_s,int vec_n=-1,char middle=' '){
    if(vec_n==-1)vec_n=vec_s.size();
    for(int i=0;i<vec_n;i++)printf("%d%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}
void array_show(vector<LL> &vec_s,int vec_n=-1,char middle=' '){
    if(vec_n==-1)vec_n=vec_s.size();
    for(int i=0;i<vec_n;i++)printf("%lld%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}

vector<vector<P>> path;
vector<LL> dis;
int id[332222][2];


int main(){
    LL n,m;
    LL i,j,k;
    LL a,b,c,d;
    cin>>n>>m;
    path.assign(n,vector<P>());
    dis.assign(n,INF);
    for(i=0;i<m;i++){
        cin>>a>>b>>c;
        a--,b--;
        path[a].push_back(make_pair(c,b));
    }
    for(i=0;i<n;i++){
        sort(path[i].begin(),path[i].end());
        id[i][1]=(int)path[i].size()-1;
    }
    typedef tuple<LL,LL,LL,LL> T;
    priority_queue<T,vector<T>,greater<T>> q1;
    q1.push(make_tuple(0,0,1,0));
    q1.push(make_tuple(0,0,0,INF));
    while(!q1.empty()){
        tie(a,b,c,d)=q1.top();q1.pop();
        dis[b]=min(dis[b],a);
        if(c==0){
            for(;id[b][0]<(int)path[b].size();id[b][0]++){
                i=id[b][0];
                if(path[b][i].first>=d)break;
                q1.push(make_tuple(a+path[b][i].first,path[b][i].second,1,path[b][i].first));
            }
        }else{
            for(;id[b][1]>=0;id[b][1]--){
                i=id[b][1];
                if(path[b][i].first<=d)break;
                q1.push(make_tuple(a+path[b][i].first,path[b][i].second,0,path[b][i].first));
            }
        }
    }
    if(dis[n-1]==INF)dis[n-1]=-1;
    cout<<dis[n-1]<<endl;
}
accuracy: 1
time_ms: 270
memory_kb: 50788
final_rank: 3

code_snippet: //
// Created by yamunaku on 2020/12/14.
//
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
//#include <atcoder/all>

using namespace std;
//using namespace atcoder;

#define rep(i, n) for(int i = 0; i < (n); i++)
#define repl(i, l, r) for(int i = (l); i < (r); i++)
#define per(i, n) for(int i = ((n)-1); i >= 0; i--)
#define perl(i, l, r) for(int i = ((r)-1); i >= (l); i--)
#define all(x) (x).begin(),(x).end()
#define MOD9 998244353
#define MOD1 1000000007
#define IINF 1000000000
#define LINF 1000000000000000000
#define SP <<" "<<
#define CYES cout<<"Yes"<<endl
#define CNO cout<<"No"<<endl
#define CFS cin.tie(0);ios::sync_with_stdio(false)
#define CST(x) cout<<fixed<<setprecision(x)

using ll = long long;
using ld = long double;
using vi = vector<int>;
using mti = vector<vector<int>>;
using vl = vector<ll>;
using mtl = vector<vector<ll>>;
using pi = pair<int, int>;
using pl = pair<ll, ll>;
template<typename T>
using heap = priority_queue<T, vector<T>, function<bool(const T, const T)>>;

int main() {
    //CFS;
    int n, m;
    cin >> n >> m;
    vi a(m), b(m), c(m);
    vector<map<int, int>> mp(n);
    rep(i, m) {
        cin >> a[i] >> b[i] >> c[i];
        a[i]--, b[i]--;
        mp[b[i]][c[i]] = 0;
    }
    mp[0][0] = 0, mp[0][IINF + 1] = 0;
    int sz = 0;
    rep(i, n) {
        for (auto &p : mp[i]) {
            p.second = sz++;
//            cout << i SP p.first SP sz - 1 << endl;
        }
    }
    vector<vector<pair<int, int>>> e(sz + sz);
    rep(i, n) {
        auto itr = mp[i].begin();
        if (itr == mp[i].end()) continue;
        int pre = itr->second;
        itr++;
        for (; itr != mp[i].end(); itr++) {
            e[pre].emplace_back(itr->second, 0);
            e[itr->second + sz].emplace_back(pre + sz, 0);
            pre = itr->second;
        }
    }
    rep(i, m) {
        auto itr = mp[a[i]].lower_bound(c[i]);
        int k = mp[b[i]][c[i]];
        if (itr != mp[a[i]].begin()) {
            itr--;
            e[itr->second].emplace_back(k + sz, c[i]);
//            cout << itr->second << ">" SP mp[b[i]][c[i]] << "<" SP c[i] SP "!" << endl;
            itr++;
        }
        if (itr != mp[a[i]].end()) {
            if (itr->first == c[i]) itr++;
            if (itr != mp[a[i]].end())
                e[itr->second + sz].emplace_back(k, c[i]);
//            cout << itr->second << "<" SP mp[b[i]][c[i]] << ">" SP
//                                                         c[i] SP "!" << endl;
        }
    }
    vl dist(sz + sz, LINF);
    priority_queue<pair<ll, int>> q;
    q.emplace(0, mp[0][0]);
    q.emplace(0, mp[0][IINF + 1] + sz);
    while (!q.empty()) {
        auto p = q.top();
        q.pop();
        int x = p.second;
        if (-p.first > dist[x]) continue;
        dist[x] = -p.first;
//        if (x >= sz) cout << x - sz << "<" SP dist[x] << endl;
//        else cout << x << ">" SP dist[x] << endl;
        for (auto &nx : e[x]) {
            ll cost = dist[x] + nx.second;
            if (cost >= dist[nx.first]) continue;
            dist[nx.first] = cost;
            q.emplace(-cost, nx.first);
        }
    }
    ll ans = LINF;
    for (auto &p : mp[n - 1]) {
        ans = min(ans, dist[p.second]);
        ans = min(ans, dist[p.second + sz]);
    }
    if (ans == LINF) cout << -1 << endl;
    else cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 450
memory_kb: 69728
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
using lint = long long;
using pint = pair<int, int>;
using plint = pair<lint, lint>;
struct fast_ios { fast_ios(){ cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(20); }; } fast_ios_;
#define ALL(x) (x).begin(), (x).end()
#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)
#define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--)
#define REP(i, n) FOR(i,0,n)
#define IREP(i, n) IFOR(i,0,n)
template <typename T, typename V>
void ndarray(vector<T>& vec, const V& val, int len) { vec.assign(len, val); }
template <typename T, typename V, typename... Args> void ndarray(vector<T>& vec, const V& val, int len, Args... args) { vec.resize(len), for_each(begin(vec), end(vec), [&](T& v) { ndarray(v, val, args...); }); }
template <typename T> bool chmax(T &m, const T q) { if (m < q) {m = q; return true;} else return false; }
template <typename T> bool chmin(T &m, const T q) { if (m > q) {m = q; return true;} else return false; }
int floor_lg(long long x) { return x <= 0 ? -1 : 63 - __builtin_clzll(x); }
template <typename T1, typename T2> pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first + r.first, l.second + r.second); }
template <typename T1, typename T2> pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first - r.first, l.second - r.second); }
template <typename T> vector<T> sort_unique(vector<T> vec) { sort(vec.begin(), vec.end()), vec.erase(unique(vec.begin(), vec.end()), vec.end()); return vec; }
template <typename T> istream &operator>>(istream &is, vector<T> &vec) { for (auto &v : vec) is >> v; return is; }
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { os << '['; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <typename T, size_t sz> ostream &operator<<(ostream &os, const array<T, sz> &arr) { os << '['; for (auto v : arr) os << v << ','; os << ']'; return os; }
#if __cplusplus >= 201703L
template <typename... T> istream &operator>>(istream &is, tuple<T...> &tpl) { std::apply([&is](auto &&... args) { ((is >> args), ...);}, tpl); return is; }
template <typename... T> ostream &operator<<(ostream &os, const tuple<T...> &tpl) { std::apply([&os](auto &&... args) { ((os << args << ','), ...);}, tpl); return os; }
#endif
template <typename T> ostream &operator<<(ostream &os, const deque<T> &vec) { os << "deq["; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <typename T> ostream &operator<<(ostream &os, const set<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T, typename TH> ostream &operator<<(ostream &os, const unordered_set<T, TH> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T> ostream &operator<<(ostream &os, const multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T> ostream &operator<<(ostream &os, const unordered_multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &pa) { os << '(' << pa.first << ',' << pa.second << ')'; return os; }
template <typename TK, typename TV> ostream &operator<<(ostream &os, const map<TK, TV> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
template <typename TK, typename TV, typename TH> ostream &operator<<(ostream &os, const unordered_map<TK, TV, TH> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
#ifdef HITONANODE_LOCAL
const string COLOR_RESET = "\033[0m", BRIGHT_GREEN = "\033[1;32m", BRIGHT_RED = "\033[1;31m", BRIGHT_CYAN = "\033[1;36m", NORMAL_CROSSED = "\033[0;9;37m", RED_BACKGROUND = "\033[1;41m", NORMAL_FAINT = "\033[0;2m";
#define dbg(x) cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << endl
#else
#define dbg(x) {}
#endif

template <typename T> struct ShortestPath {
    int V, E;
    int INVALID = -1;
    std::vector<std::vector<std::pair<int, T>>> to;
    ShortestPath() = default;
    ShortestPath(int V) : V(V), E(0), to(V) {}
    void add_edge(int s, int t, T len) {
        assert(0 <= s and s < V);
        assert(0 <= t and t < V);
        to[s].emplace_back(t, len);
        E++;
    }

    std::vector<T> dist;
    std::vector<int> prev;
    // Dijkstra algorithm
    // Complexity: O(E log E)
    void Dijkstra(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, std::numeric_limits<T>::max());
        dist[s] = 0;
        prev.assign(V, INVALID);
        using P = std::pair<T, int>;
        std::priority_queue<P, std::vector<P>, std::greater<P>> pq;
        pq.emplace(0, s);
        while (!pq.empty()) {
            T d;
            int v;
            std::tie(d, v) = pq.top();
            pq.pop();
            if (dist[v] < d) continue;
            for (auto nx : to[v]) {
                T dnx = d + nx.second;
                if (dist[nx.first] > dnx) {
                    dist[nx.first] = dnx, prev[nx.first] = v;
                    pq.emplace(dnx, nx.first);
                }
            }
        }
    }
};

int main()
{
    int N, M;
    cin >> N >> M;
    vector<vector<int>> v2d(N);
    vector<vector<pint>> to(N);
    while (M--) {
        int a, b, c;
        cin >> a >> b >> c;
        a--, b--;
        v2d[a].emplace_back(c), v2d[b].emplace_back(c);
        to[a].emplace_back(b, c);
    }
    for (auto &vec : v2d) vec = sort_unique(vec);

    vector<int> H(N * 2 + 1);
    REP(i, N * 2) H[i + 1] = H[i] + v2d[i % N].size();

    const int gs = H.back(), gt = gs + 1;
    ShortestPath<lint> graph(gt + 1);
    REP(i, N) FOR(j, H[i] + 1, H[i + 1]) graph.add_edge(j - 1, j, 0);
    FOR(i, N, N * 2) FOR(j, H[i] + 1, H[i + 1]) graph.add_edge(j, j - 1, 0);
    graph.add_edge(gs, 0, 0);
    graph.add_edge(gs, H[N + 1] - 1, 0);
    graph.add_edge(H[N] - 1, gt, 0);
    graph.add_edge(H[N * 2 - 1], gt, 0);

    REP(i, N) {
        for (auto [j, d] : to[i]) {
            int di = lower_bound(v2d[i].begin(), v2d[i].end(), d) - v2d[i].begin();
            int dj = lower_bound(v2d[j].begin(), v2d[j].end(), d) - v2d[j].begin();
            if (dj) graph.add_edge(H[i] + di, H[N + j] + dj - 1, d);
            if (dj + 1 < int(v2d[j].size())) graph.add_edge(H[N + i] + di, H[j] + dj + 1, d);
            if (j == N - 1) graph.add_edge(H[i] + di, gt, d);
            if (j == N - 1) graph.add_edge(H[N + i] + di, gt, d);
        }
    }
    graph.Dijkstra(gs);
    lint ret = graph.dist[gt];
    cout << (ret >= 1e18 ? -1 : ret) << '\n';
}
accuracy: 1
time_ms: 220
memory_kb: 108828
final_rank: 4

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC target ("sse4")

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
    ll res = 1;
    while (n) {
        if (n & 1)res = res * x % m;
        x = x * x % m; n >>= 1;
    }
    return res;
}
struct modint {
    ll n;
    modint() :n(0) { ; }
    modint(ll m) :n(m) {
        if (n >= mod)n %= mod;
        else if (n < 0)n = (n % mod + mod) % mod;
    }
    operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
    if (n == 0)return modint(1);
    modint res = (a * a) ^ (n / 2);
    if (n % 2)res = res * a;
    return res;
}

ll inv(ll a, ll p) {
    return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }

const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
    fact[0] = modint(1);
    for (int i = 0; i < max_n - 1; i++) {
        fact[i + 1] = fact[i] * modint(i + 1);
    }
    factinv[max_n - 1] = modint(1) / fact[max_n - 1];
    for (int i = max_n - 2; i >= 0; i--) {
        factinv[i] = factinv[i + 1] * modint(i + 1);
    }
}
modint comb(int a, int b) {
    if (a < 0 || b < 0 || a < b)return 0;
    return fact[a] * factinv[b] * factinv[a - b];
}

struct edge {
    int to, cost;
};
void solve() {
    int n, m; cin >> n >> m;

    vector<vector<int>> costs(n);
    rep(i, n) {
        costs[i].push_back(-1);
        costs[i].push_back(1000000007);
    }
    vector<pair<P, int>> es;
    rep(i, m) {
        int a, b, c; cin >> a >> b >> c; a--; b--;
        es.push_back({ {a,b},c });
        costs[a].push_back(c);
        costs[b].push_back(c);
    }
    vector<int> ad(n);
    int sum = 0;
    rep(i, n) {
        ad[i] = sum;
        sort(all(costs[i]));
        costs[i].erase(unique(all(costs[i])), costs[i].end());
        sum += costs[i].size();
    }
    //up,down
    vector<vector<edge>> G(2 * sum);
    rep(i, n) {
        rep(j, costs[i].size()-1) {
            G[ad[i] + j].push_back({ ad[i] + j + 1,0 });
            G[ad[i] + j + 1 + sum].push_back({ ad[i] + j + sum,0 });
        }
    }
    for (pair<P, int> p : es) {
        int a = p.first.first;
        int b = p.first.second;
        int c = p.second;
        int le = ad[a] + (lower_bound(all(costs[a]), c) - costs[a].begin());
        int ri = ad[b] + (lower_bound(all(costs[b]), c) - costs[b].begin());
        G[le].push_back({ ri - 1 + sum,c });
        G[le + sum].push_back({ ri + 1,c });
    }
    vector<ll> dist(2 * sum, INF);
    priority_queue<LP, vector<LP>, greater<LP>> q;
    dist[0] = 0; q.push({ 0,0 });
    dist[costs[0].size() - 1 + sum] = 0; q.push({ 0,costs[0].size() - 1 + sum });
    while (!q.empty()) {
        LP p = q.top(); q.pop();
        int v = p.second;
        if (dist[v] < p.first)continue;
        for (edge e : G[v]) {
            ll nd = e.cost + dist[v];
            if (nd < dist[e.to]) {
                dist[e.to] = nd;
                q.push({ nd,e.to });
            }
        }
    }
    ll ans = INF;
    rep(j, costs[n - 1].size()) {
        ans = min(ans, dist[ad[n - 1] + j]);
        ans = min(ans, dist[ad[n - 1] + j + sum]);
    }
    if (ans == INF)ans = -1;
    cout << ans << "\n";

}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    //cout << fixed << setprecision(15);
    //init_f();
    //init();
    //expr();
    //int t; cin >> t; rep(i, t)
    solve();
    return 0;
}
accuracy: 1
time_ms: 410
memory_kb: 182808
final_rank: 9

code_snippet: #line 2 "/Users/tiramister/CompetitiveProgramming/Cpp/CppLibrary/Tools/compress.hpp"

#include <algorithm>
#include <vector>
#include <map>

template <class T>
std::map<T, int> compress(std::vector<T>& v) {
    std::sort(v.begin(), v.end());
    v.erase(std::unique(v.begin(), v.end()), v.end());

    std::map<T, int> rev;
    for (int i = 0; i < (int)v.size(); ++i) rev[v[i]] = i;
    return rev;
}
#line 2 "/Users/tiramister/CompetitiveProgramming/Cpp/CppLibrary/Graph/dijkstra.hpp"

#line 2 "/Users/tiramister/CompetitiveProgramming/Cpp/CppLibrary/Tools/heap_alias.hpp"

#include <queue>

template <class T>
using MaxHeap = std::priority_queue<T>;
template <class T>
using MinHeap = std::priority_queue<T, std::vector<T>, std::greater<T>>;
#line 2 "/Users/tiramister/CompetitiveProgramming/Cpp/CppLibrary/Graph/graph.hpp"

#line 4 "/Users/tiramister/CompetitiveProgramming/Cpp/CppLibrary/Graph/graph.hpp"

template <class Cost = int>
struct Edge {
    int src, dst;
    Cost cost;

    Edge() = default;
    Edge(int src, int dst, Cost cost = 1)
        : src(src), dst(dst), cost(cost){};

    bool operator<(const Edge<Cost>& e) const { return cost < e.cost; }
    bool operator>(const Edge<Cost>& e) const { return cost > e.cost; }
};

template <class Cost = int>
struct Graph : public std::vector<std::vector<Edge<Cost>>> {
    using std::vector<std::vector<Edge<Cost>>>::vector;

    void span(bool direct, int src, int dst, Cost cost = 1) {
        (*this)[src].emplace_back(src, dst, cost);
        if (!direct) (*this)[dst].emplace_back(dst, src, cost);
    }
};
#line 5 "/Users/tiramister/CompetitiveProgramming/Cpp/CppLibrary/Graph/dijkstra.hpp"

template <class Cost>
std::vector<Cost> dijkstra(const Graph<Cost>& graph, int s) {
    std::vector<Cost> dist(graph.size(), -1);
    dist[s] = 0;
    MinHeap<std::pair<Cost, int>> que;
    que.emplace(0, s);

    while (!que.empty()) {
        auto [d, v] = que.top();
        que.pop();
        if (d > dist[v]) continue;

        for (const auto& e : graph[v]) {
            if (dist[e.dst] != -1 &&
                dist[e.dst] <= dist[v] + e.cost) continue;
            dist[e.dst] = dist[v] + e.cost;
            que.emplace(dist[e.dst], e.dst);
        }
    }

    return dist;
}
#line 3 "main.cpp"
#include <iostream>
#line 6 "main.cpp"

using namespace std;

using lint = long long;
constexpr lint INF = 1LL << 30;

void solve() {
    int n, m;
    cin >> n >> m;

    vector<Edge<lint>> es(m);
    vector<vector<lint>> dss(n, {0, INF});
    for (auto& e : es) {
        cin >> e.src >> e.dst >> e.cost;
        dss[--e.src].push_back(e.cost);
        dss[--e.dst].push_back(e.cost);
    }

    vector<int> bs(n);
    vector<map<lint, int>> drevs(n);

    int b = 0;
    for (int v = 0; v < n; ++v) {
        drevs[v] = compress(dss[v]);
        bs[v] = b;
        b += dss[v].size();
    }

    int s = b * 2, g = s + 1;
    Graph<lint> graph(b * 2 + 2);
    // 0がlow, 1がhigh
    for (int v = 0; v < n; ++v) {
        int k = dss[v].size();
        for (int i = 0; i < k; ++i) {
            if (i - 1 >= 0) graph.span(true, bs[v] + i, bs[v] + i - 1, 0);
            if (i + 1 < k) graph.span(true, bs[v] + i + b, bs[v] + i + 1 + b, 0);
        }
    }

    {
        int v = 0;
        int k = dss[v].size();
        for (int i = 0; i < k; ++i) {
            graph.span(true, s, bs[v] + i, 0);
            graph.span(true, s, bs[v] + i + b, 0);
        }
    }

    {
        int v = n - 1;
        int k = dss[v].size();
        for (int i = 0; i < k; ++i) {
            graph.span(true, bs[v] + i, g, 0);
            graph.span(true, bs[v] + i + b, g, 0);
        }
    }

    auto enc = [&](int v, lint d, int t) {
        return bs[v] + drevs[v][d] + t * b;
    };

    for (auto e : es) {
        // low -> high
        graph.span(true, enc(e.src, e.cost, 0), enc(e.dst, e.cost, 1) + 1, e.cost);
        // high -> low
        graph.span(true, enc(e.src, e.cost, 1), enc(e.dst, e.cost, 0) - 1, e.cost);
    }

    auto ans = dijkstra(graph, s)[g];
    cout << ans << "\n";
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    solve();

    return 0;
}
accuracy: 1
time_ms: 750
memory_kb: 280092
final_rank: 12

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

//////////////////////////////   Begin Macros

#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define in(x, a, b) (a <= x and x < b)
#define rep(i, N) for (int i = 0; i < (int)(N); i++)
#define reprev(i, N) for (int i = (int)(N)-1; i >= 0; i--)
#define rep1(i, N) for (int i = 1; i <= (int)(N); i++)
#define rep1rev(i, N) for (int i = (int)(N); i >= 0; i--)
#define forbe(i, b, e) for (int i = (b); i < (e); i++)
#define forberev(i, b, e) for (int i = (e)-1; i >= (b); i--)
#define forfl(i, f, l) for (int i = (f); i <= (l); i++)
#define forflrev(i, f, l) for (int i = (l); i >= (f); i--)
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;

template <typename T>
bool chmax(T &m, const T q)
{
  if (m < q)
  {
    m = q;
    return true;
  }
  else
    return false;
}
template <typename T>
bool chmin(T &m, const T q)
{
  if (m > q)
  {
    m = q;
    return true;
  }
  else
    return false;
}
template <typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return {l.first + r.first, l.second + r.second}; }
template <typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return {l.first - r.first, l.second - r.second}; }
template <typename T>
pair<T, T> operator*(const pair<T, T> &l, const T &r) { return {l.first * r, l.second * r}; }
template <typename T>
pair<T, T> operator/(const pair<T, T> &l, const T &r) { return {l.first / r, l.second / r}; }
template <typename T>
istream &operator>>(istream &is, vector<T> &vec)
{
  for (auto &v : vec)
    is >> v;
  return is;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &vec)
{
  os << "[";
  for (auto v : vec)
    os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const deque<T> &vec)
{
  os << "deq[";
  for (auto v : vec)
    os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const set<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_set<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const multiset<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_multiset<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &pa)
{
  is >> pa.first >> pa.second;
  return is;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &pa)
{
  os << "(" << pa.first << "," << pa.second << ")";
  return os;
}
template <typename... Ts>
istream &operator>>(istream &is, tuple<Ts...> &theTuple)
{
  apply([&is](Ts &... tupleArgs) { ((is >> tupleArgs), ...); }, theTuple);
  return is;
}
template <typename... Ts>
ostream &operator<<(ostream &os, const tuple<Ts...> &theTuple)
{
  apply([&os](const Ts &... tupleArgs) {
    os << '(';
    size_t n(0);
    ((os << tupleArgs << (++n < sizeof...(Ts) ? "," : "")), ...);
    os << ')';
  },
        theTuple);
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const map<TK, TV> &mp)
{
  os << "{";
  for (auto v : mp)
    os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp)
{
  os << "{";
  for (auto v : mp)
    os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}

template <typename T>
void reset(vector<T> &v, const T reset_to)
{
  for (auto &x : v)
    x = reset_to;
}
inline int popcount(const unsigned int x) { return __builtin_popcount(x); }
// #define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << endl;

ll nC2(ll n)
{
  return n * (n - 1) / 2;
}

const int intinf = numeric_limits<int>::max();
const ll llinf = numeric_limits<ll>::max();
const pii udlr[4] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

//////////////////////////////   End Macros

// Graph.h start--------------------------------------------

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

template <typename Weight>
struct Vertex;
template <typename Weight>
struct Edge;

template <typename Weight>
struct Vertex
{
  int id;
  vector<int> ids_dst;
  vector<Edge<Weight>> edges;

  Vertex(const int id = 0) : id(id){};
  int &operator[](int n) { return ids_dst[n]; }
  const int &operator[](int n) const { return ids_dst[n]; }

  size_t size() const { return edges.size(); }
  void add_edge(const Edge<Weight> &);
};

template <typename Weight>
struct Edge
{
  int id_src, id_dst;
  Weight weight;

  Edge(const int id_src, const int id_dst) : id_src(id_src), id_dst(id_dst){};
  Edge(const int id_src, const int id_dst, const Weight weight) : id_src(id_src), id_dst(id_dst), weight(weight){};
};
template <typename Weight>
ostream &operator<<(ostream &os, const Edge<Weight> &e) { return os << "Edge(" << e.id_src << "->" << e.id_dst << "," << e.weight << ")"; }

template <typename Weight = long long>
struct Graph
{
  vector<Vertex<Weight>> vertices;
  vector<Edge<Weight>> edges;

  Graph(const int nvertices = 0);
  Vertex<Weight> &operator[](int n) { return vertices[n]; }
  const Vertex<Weight> &operator[](int n) const { return vertices[n]; }

  size_t size() const { return vertices.size(); }
  void add_edge(const Edge<Weight> &);
  void add_edge(const int id_src, const int id_dst) { add_edge({id_src, id_dst}); };
  void add_edge(const int id_src, const int id_dst, const Weight w) { add_edge({id_src, id_dst, w}); };
};
template <typename Weight>
ostream &operator<<(ostream &os, const Graph<Weight> &g)
{
  cout << "Graph(" << g.size() << ")"
       << "[" << endl;
  for (auto &e : g.edges)
    os << " " << e << "," << endl;
  cout << "]";
  return os;
}

//----------------------------------------------------------

template <typename Weight>
void Vertex<Weight>::add_edge(const Edge<Weight> &e)
{
  edges.push_back(e);
  ids_dst.push_back(e.id_dst);
}

template <typename Weight>
bool operator<(const Edge<Weight> &e1, const Edge<Weight> &e2)
{
  return e1.weight != e2.weight ? e1.weight > e2.weight : // !!INVERSE!!
             e1.id_src != e2.id_src ? e1.id_src < e2.id_src : e1.id_dst < e2.id_dst;
}

template <typename Weight>
Graph<Weight>::Graph(const int nvertices)
{
  for (int id = 0; id < nvertices; id++)
    vertices.emplace_back(id);
}
template <typename Weight>
void Graph<Weight>::add_edge(const Edge<Weight> &e)
{
  edges.push_back(e);
  vertices[e.id_src].add_edge(e);
}

template <typename Weight>
Graph<Weight> make_tree(Graph<Weight> &g)
{
  int nvertices = g.size();
  Graph<Weight> g_tree(nvertices);
  queue<int> q;
  vector<bool> is_used(nvertices, false);

  int v_start = 0;
  q.push(v_start);
  is_used[v_start] = true;
  while (!q.empty())
  {
    int v = q.front();
    q.pop();
    for (int c : g[v].ids_dst)
    {
      if (is_used[c])
        continue;
      g_tree.add_edge(v, c);
      g_tree.add_edge(c, v);
      q.push(c);
      is_used[c] = true;
    }
  }

  return g_tree;
}

// Graph.h end----------------------------------------------

// ShortPath.h start----------------------------------------

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

template <typename Weight>
vector<Weight> dijkstra(const Graph<Weight> &g, const int id_start, const Weight INF);
template <typename Weight>
vector<Weight> bellman_ford(const Graph<Weight> &g, const int id_start, const Weight INF);
template <typename Weight>
vector<vector<Weight>> warshall_floyd(const Graph<Weight> &g, const Weight INF);

//----------------------------------------------------------

template <typename Weight>
vector<Weight> dijkstra(const Graph<Weight> &g, const int id_start, const Weight INF)
{
  int n = g.size();
  using Pwi = pair<Weight, int>;
  vector<Weight> d(n, INF);
  d[id_start] = 0;
  vector<bool> is_used(n, false);
  priority_queue<Pwi, vector<Pwi>, greater<Pwi>> que;

  que.push(Pwi(0, id_start));
  while (!que.empty())
  {
    const int id_src = que.top().second; // que.top().first >= d[id_src]
    que.pop();

    if (is_used[id_src])
      continue;
    is_used[id_src] = true;

    for (const auto &edge : g.vertices[id_src].edges)
    {
      const int id_dst = edge.id_dst;
      if (d[id_dst] <= d[id_src] + edge.weight)
        continue;

      d[id_dst] = d[id_src] + edge.weight;
      que.push(Pwi(d[id_dst], id_dst));
    }
  }

  return d;
}

template <typename Weight>
vector<Weight> bellman_ford(const Graph<Weight> &g, const int id_start, const Weight INF)
{
  // INF�ɋC��t���� d_max < INF
  // ���̕H����A�N�Z�X�ł��钸�_�ɂ�d = -INF
  const int n = (int)g.vertices.size();
  vector<Weight> d(n, INF);
  d[id_start] = 0;
  bool is_negative_cycle = false;
  for (int i = 1; i <= n; i++)
  {
    for (const auto &edge : g.edges)
    {
      const int id_src = edge.id_src;
      const int id_dst = edge.id_dst;
      if (d[id_src] == INF)
        continue;

      if (d[id_dst] > d[id_src] + edge.weight)
      {
        d[id_dst] = d[id_src] + edge.weight;
        if (i < n)
          continue;

        d[id_dst] = -INF;
        is_negative_cycle = true;
      }
    }
  }

  if (!is_negative_cycle)
    return d;

  for (int i = 1; i < n; i++)
  {
    for (const auto &edge : g.edges)
    {
      const int id_src = edge.id_src;
      const int id_dst = edge.id_dst;
      if (d[id_src] == -INF && d[id_dst] != -INF)
        d[id_dst] = -INF;
    }
  }

  return d;
}

template <typename Weight>
vector<vector<Weight>> warshall_floyd(const Graph<Weight> &g, const Weight INF)
{
  const int n = g.size();
  vector<vector<Weight>> d(n, vector<Weight>(n, INF));
  for (size_t id = 0; id < n; id++)
    d[id][id] = 0;

  for (const auto &edge : g.edges)
    d[edge.id_src][edge.id_dst] = edge.weight;
  for (int id_new = 0; id_new < n; id_new++)
    for (int id_src = 0; id_src < n; id_src++)
      for (int id_dst = 0; id_dst < n; id_dst++)
        if (d[id_src][id_dst] > d[id_src][id_new] + d[id_new][id_dst])
          d[id_src][id_dst] = d[id_src][id_new] + d[id_new][id_dst];

  return d;
}

// ShortPath.h end------------------------------------------

void solve()
{
  const string IMPOSSIBLE = "-1";
  using Weight = ll;
  int n, m;
  cin >> n >> m;
  const int v_start = 0, v_goal = n - 1;
  vector<int> a(m), b(m);
  vector<Weight> cc(m);
  rep(j, m)
  {
    cin >> a[j] >> b[j] >> cc[j];
    a[j]--;
    b[j]--;
  }

  vector<set<Weight>> in_i2costs(n), out_i2costs(n);
  rep(j, m)
  {
    out_i2costs[a[j]].insert(cc[j]);
    in_i2costs[b[j]].insert(cc[j]);
  }

  map<int, int> vipc2k[300000][2][2];
  // map<int, int> vipc2k[30005][2][2];
  int s, t;
  {
    int cnt = 0;
    rep(v, n) rep(pm, 2)
    {
      for (auto c : in_i2costs[v])
      {
        vipc2k[v][0][pm][pm == 0 ? c : -c] = cnt++;
      }
      for (auto c : out_i2costs[v])
      {
        vipc2k[v][1][pm][pm == 0 ? c : -c] = cnt++;
      }
    }
    s = cnt;
    t = cnt + 1;
  }
  Graph<Weight> g(t + 1);

  rep(v, n) rep(pm, 2)
  {
    // in to out
    for (auto [c, from] : vipc2k[v][0][pm])
    {
      auto it = vipc2k[v][1][pm].upper_bound(c);
      if (it == vipc2k[v][1][pm].end())
        continue;
      int to = it->second;
      g.add_edge(from, to, 0);
    }

    // in to in, out to out
    for (auto it = vipc2k[v][1][pm].begin(); it != vipc2k[v][1][pm].end(); it++)
    {
      auto from = it->second;
      it++;
      if (it == vipc2k[v][1][pm].end())
        break;
      auto to = it->second;
      it--;
      g.add_edge(from, to, 0);
    }
  }

  // a to b
  rep(j, m) rep(pm, 2)
  {
    Weight c = cc[j];
    auto from = vipc2k[a[j]][1][pm][(pm == 0 ? c : -c)];
    int npm = pm == 0 ? 1 : 0;
    auto to = vipc2k[b[j]][0][npm][(npm == 0 ? c : -c)];
    g.add_edge(from, to, c);
  }

  // s to start, goal to t
  rep(pm, 2)
  {
    for (auto [c, to] : vipc2k[v_start][1][pm])
    {
      g.add_edge(s, to, 0);
    }
    for (auto [c, from] : vipc2k[v_goal][0][pm])
    {
      g.add_edge(from, t, 0);
    }
  }

  const ll INF = llinf - 1000000000000;
  auto dist = dijkstra(g, s, INF);
  if (dist[t] == INF)
  {
    cout << IMPOSSIBLE << endl;
  }
  else
  {
    cout << dist[t] << endl;
  }

  // dbg(g);
  // rep(v, n) rep(io, 2) rep(pm, 2)
  // {
  //   cout << "v: " << v << (io == 0 ? " in" : " out") << (pm == 0 ? " + " : " - ") << vipc2k[v][io][pm] << endl;
  // }
}

int main()
{
  cin.tie(0);
  ios::sync_with_stdio(false);
  // cerr << "start" << endl;
  srand(time(0));
  cout << fixed << setprecision(15);

  solve();
  return 0;
}
accuracy: 1
time_ms: 1010
memory_kb: 366688
final_rank: 15

code_snippet: #include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <list>
#include <iterator>
#include <cassert>
#include <numeric>
#include <functional>
#include <time.h>
#pragma warning(disable:4996) 

//#define ATCODER
#ifdef ATCODER
#include <atcoder/all>
#endif

typedef long long ll;
typedef unsigned long long ull;
#define LINF  9223300000000000000
#define LINF2 1223300000000000000
#define LINF3 1000000000000
#define INF 2140000000
const long long MOD = 1000000007;
//const long long MOD = 998244353;

using namespace std;
#ifdef ATCODER
using namespace atcoder;
#endif

typedef pair<ll, int> P;
vector<ll> dijkstra(int s, const vector<vector<pair<int, int> > >& G) {
    priority_queue< P, vector<P>, greater<P> > que;
    vector<ll> d(G.size(), LINF);
    d[s] = 0;
    que.push(P(0, s));
    while (!que.empty()) {
        int curr = que.top().second;
        ll  dcurr = que.top().first;
        que.pop();
        if (d[curr] < dcurr) continue;
        int i;
        for (i = 0; i < (int)G[curr].size(); i++) {
            int next = G[curr][i].first;
            ll  dist = G[curr][i].second;
            if (d[next] > d[curr] + dist) {
                d[next] = d[curr] + dist;
                que.push(P(d[next], next));
            }
        }
    }
    return d;
}

void solve()
{
    int n, m;
    scanf("%d%d", &n, &m);
    vector<int> a(m), b(m), c(m);
    vector<vector<pair<int,int> > > s0(n), s1(n);    // in edges (cost,id), out edges (cost,id) for each vertex
    int i;
    for (i = 0; i < m; i++) {
        scanf("%d%d%d", &a[i], &b[i], &c[i]); a[i]--; b[i]--;
        s0[b[i]].push_back(make_pair(c[i],i));
        s1[a[i]].push_back(make_pair(c[i],i));
    }
    for (i = 0; i < n; i++) {
        sort(s0[i].begin(), s0[i].end());
        sort(s1[i].begin(), s1[i].end());
    }

    vector<vector<pair<int, int> > > g(m*2+2);      // [2*i]:large, [2*i+1]:small,  [2*m]:start, [2*m+1]:end

    // create edge around each vertex
    for (i = 0; i < n; i++) {
        auto it0 = s0[i].begin();
        for (; it0 != s0[i].end(); ++it0) {
            int cost0 = it0->first;
            int id0 =it0->second;
            {
                auto it1 = lower_bound(s1[i].begin(),s1[i].end(),make_pair(cost0 + 1, -INF));
                if (it1 != s1[i].end()) {
                    int cost1 = it1->first;
                    int id1 = it1->second;
                    g[2 * id0 + 1].push_back(make_pair(id1 * 2, cost0 + cost1));
                }
            }
            {
                auto it1 = lower_bound(s1[i].begin(), s1[i].end(), make_pair(cost0, -INF));
                if (it1 != s1[i].begin()) {
                    it1--;
                    int cost1 = it1->first;
                    int id1 = it1->second;
                    g[2 * id0].push_back(make_pair(id1 * 2+1, 0));
                }
            }
        }
        {
            auto it1 = s1[i].begin();
            int costprev = 0;
            int prev = -1;
            for (; it1 != s1[i].end(); ++it1) {
                int costcurr = it1->first;
                int curr = it1->second;
                if (prev >= 0) {
                    g[2 * prev].push_back(make_pair(2*curr, costcurr-costprev));
                }
                prev = curr;
                costprev = costcurr;
            }
        }
        {
            auto it1 = s1[i].rbegin();
            int prev = -1;
            for (; it1 != s1[i].rend(); ++it1) {
                int curr = it1->second;
                if (prev >= 0) {
                    g[2 * prev+1].push_back(make_pair(2 * curr+1, 0));
                }
                prev = curr;
            }
        }
    }

    // create edges from start point [2*m]
    {
        auto it = s1[0].begin();
        if (it != s1[0].end()) {
            int cost = it->first;
            int id1 = it->second;
            g[2 * m].push_back(make_pair(id1 * 2, cost));
        }
    }
    {
        auto it = s1[0].rbegin();
        if (it != s1[0].rend()) {
            int cost = it->first;
            int id1 = it->second;
            g[2 * m].push_back(make_pair(id1 * 2+1, 0));
        }
    }

    // create eges to end point [2*m+1]
    {
        auto it = s0[n-1].begin();
        for (; it != s0[n - 1].end(); ++it) {
            int cost = it->first;
            int id1 = it->second;
            g[2 * id1].push_back(make_pair(2*m+1, 0));
            g[2 * id1+1].push_back(make_pair(2 * m + 1, cost));
        }
    }

    // calculate
    vector<ll> dist = dijkstra(2 * m, g);
    if (dist[2 * m + 1] < LINF) {
        printf("%lld\n", dist[2 * m + 1]);
    }
    else {
        printf("-1\n");
    }

    return;
}

int main()
{
#if 1
    solve();
#else
    int T;
    scanf("%d", &T);
    int t;
    for (t = 0; t < T; t++) {
        //printf("Case #%d: ", t + 1);
        solve();
    }
#endif
    return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 66848
final_rank: 2

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

//////////////////////////////   Begin Macros

#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define in(x, a, b) (a <= x and x < b)
#define rep(i, N) for (int i = 0; i < (int)(N); i++)
#define reprev(i, N) for (int i = (int)(N)-1; i >= 0; i--)
#define rep1(i, N) for (int i = 1; i <= (int)(N); i++)
#define rep1rev(i, N) for (int i = (int)(N); i >= 0; i--)
#define forbe(i, b, e) for (int i = (b); i < (e); i++)
#define forberev(i, b, e) for (int i = (e)-1; i >= (b); i--)
#define forfl(i, f, l) for (int i = (f); i <= (l); i++)
#define forflrev(i, f, l) for (int i = (l); i >= (f); i--)
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;

template <typename T>
bool chmax(T &m, const T q)
{
  if (m < q)
  {
    m = q;
    return true;
  }
  else
    return false;
}
template <typename T>
bool chmin(T &m, const T q)
{
  if (m > q)
  {
    m = q;
    return true;
  }
  else
    return false;
}
template <typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return {l.first + r.first, l.second + r.second}; }
template <typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return {l.first - r.first, l.second - r.second}; }
template <typename T>
pair<T, T> operator*(const pair<T, T> &l, const T &r) { return {l.first * r, l.second * r}; }
template <typename T>
pair<T, T> operator/(const pair<T, T> &l, const T &r) { return {l.first / r, l.second / r}; }
template <typename T>
istream &operator>>(istream &is, vector<T> &vec)
{
  for (auto &v : vec)
    is >> v;
  return is;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &vec)
{
  os << "[";
  for (auto v : vec)
    os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const deque<T> &vec)
{
  os << "deq[";
  for (auto v : vec)
    os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const set<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_set<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const multiset<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_multiset<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &pa)
{
  is >> pa.first >> pa.second;
  return is;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &pa)
{
  os << "(" << pa.first << "," << pa.second << ")";
  return os;
}
template <typename... Ts>
istream &operator>>(istream &is, tuple<Ts...> &theTuple)
{
  apply([&is](Ts &... tupleArgs) { ((is >> tupleArgs), ...); }, theTuple);
  return is;
}
template <typename... Ts>
ostream &operator<<(ostream &os, const tuple<Ts...> &theTuple)
{
  apply([&os](const Ts &... tupleArgs) {
    os << '(';
    size_t n(0);
    ((os << tupleArgs << (++n < sizeof...(Ts) ? "," : "")), ...);
    os << ')';
  },
        theTuple);
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const map<TK, TV> &mp)
{
  os << "{";
  for (auto v : mp)
    os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp)
{
  os << "{";
  for (auto v : mp)
    os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}

template <typename T>
void reset(vector<T> &v, const T reset_to)
{
  for (auto &x : v)
    x = reset_to;
}
inline int popcount(const unsigned int x) { return __builtin_popcount(x); }
// #define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << endl;

ll nC2(ll n)
{
  return n * (n - 1) / 2;
}

const int intinf = numeric_limits<int>::max();
const ll llinf = numeric_limits<ll>::max();
const pii udlr[4] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

//////////////////////////////   End Macros

// Graph.h start--------------------------------------------

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

template <typename Weight>
struct Vertex;
template <typename Weight>
struct Edge;

template <typename Weight>
struct Vertex
{
  int id;
  vector<int> ids_dst;
  vector<Edge<Weight>> edges;

  Vertex(const int id = 0) : id(id){};
  int &operator[](int n) { return ids_dst[n]; }
  const int &operator[](int n) const { return ids_dst[n]; }

  size_t size() const { return edges.size(); }
  void add_edge(const Edge<Weight> &);
};

template <typename Weight>
struct Edge
{
  int id_src, id_dst;
  Weight weight;

  Edge(const int id_src, const int id_dst) : id_src(id_src), id_dst(id_dst){};
  Edge(const int id_src, const int id_dst, const Weight weight) : id_src(id_src), id_dst(id_dst), weight(weight){};
};
template <typename Weight>
ostream &operator<<(ostream &os, const Edge<Weight> &e) { return os << "Edge(" << e.id_src << "->" << e.id_dst << "," << e.weight << ")"; }

template <typename Weight = long long>
struct Graph
{
  vector<Vertex<Weight>> vertices;
  vector<Edge<Weight>> edges;

  Graph(const int nvertices = 0);
  Vertex<Weight> &operator[](int n) { return vertices[n]; }
  const Vertex<Weight> &operator[](int n) const { return vertices[n]; }

  size_t size() const { return vertices.size(); }
  void add_edge(const Edge<Weight> &);
  void add_edge(const int id_src, const int id_dst) { add_edge({id_src, id_dst}); };
  void add_edge(const int id_src, const int id_dst, const Weight w) { add_edge({id_src, id_dst, w}); };
};
template <typename Weight>
ostream &operator<<(ostream &os, const Graph<Weight> &g)
{
  cout << "Graph(" << g.size() << ")"
       << "[" << endl;
  for (auto &e : g.edges)
    os << " " << e << "," << endl;
  cout << "]";
  return os;
}

//----------------------------------------------------------

template <typename Weight>
void Vertex<Weight>::add_edge(const Edge<Weight> &e)
{
  edges.push_back(e);
  ids_dst.push_back(e.id_dst);
}

template <typename Weight>
bool operator<(const Edge<Weight> &e1, const Edge<Weight> &e2)
{
  return e1.weight != e2.weight ? e1.weight > e2.weight : // !!INVERSE!!
             e1.id_src != e2.id_src ? e1.id_src < e2.id_src : e1.id_dst < e2.id_dst;
}

template <typename Weight>
Graph<Weight>::Graph(const int nvertices)
{
  for (int id = 0; id < nvertices; id++)
    vertices.emplace_back(id);
}
template <typename Weight>
void Graph<Weight>::add_edge(const Edge<Weight> &e)
{
  edges.push_back(e);
  vertices[e.id_src].add_edge(e);
}

template <typename Weight>
Graph<Weight> make_tree(Graph<Weight> &g)
{
  int nvertices = g.size();
  Graph<Weight> g_tree(nvertices);
  queue<int> q;
  vector<bool> is_used(nvertices, false);

  int v_start = 0;
  q.push(v_start);
  is_used[v_start] = true;
  while (!q.empty())
  {
    int v = q.front();
    q.pop();
    for (int c : g[v].ids_dst)
    {
      if (is_used[c])
        continue;
      g_tree.add_edge(v, c);
      g_tree.add_edge(c, v);
      q.push(c);
      is_used[c] = true;
    }
  }

  return g_tree;
}

// Graph.h end----------------------------------------------

// ShortPath.h start----------------------------------------

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

template <typename Weight>
vector<Weight> dijkstra(const Graph<Weight> &g, const int id_start, const Weight INF);
template <typename Weight>
vector<Weight> bellman_ford(const Graph<Weight> &g, const int id_start, const Weight INF);
template <typename Weight>
vector<vector<Weight>> warshall_floyd(const Graph<Weight> &g, const Weight INF);

//----------------------------------------------------------

template <typename Weight>
vector<Weight> dijkstra(const Graph<Weight> &g, const int id_start, const Weight INF)
{
  int n = g.size();
  using Pwi = pair<Weight, int>;
  vector<Weight> d(n, INF);
  d[id_start] = 0;
  vector<bool> is_used(n, false);
  priority_queue<Pwi, vector<Pwi>, greater<Pwi>> que;

  que.push(Pwi(0, id_start));
  while (!que.empty())
  {
    const int id_src = que.top().second; // que.top().first >= d[id_src]
    que.pop();

    if (is_used[id_src])
      continue;
    is_used[id_src] = true;

    for (const auto &edge : g.vertices[id_src].edges)
    {
      const int id_dst = edge.id_dst;
      if (d[id_dst] <= d[id_src] + edge.weight)
        continue;

      d[id_dst] = d[id_src] + edge.weight;
      que.push(Pwi(d[id_dst], id_dst));
    }
  }

  return d;
}

template <typename Weight>
vector<Weight> bellman_ford(const Graph<Weight> &g, const int id_start, const Weight INF)
{
  // INF�ɋC��t���� d_max < INF
  // ���̕H����A�N�Z�X�ł��钸�_�ɂ�d = -INF
  const int n = (int)g.vertices.size();
  vector<Weight> d(n, INF);
  d[id_start] = 0;
  bool is_negative_cycle = false;
  for (int i = 1; i <= n; i++)
  {
    for (const auto &edge : g.edges)
    {
      const int id_src = edge.id_src;
      const int id_dst = edge.id_dst;
      if (d[id_src] == INF)
        continue;

      if (d[id_dst] > d[id_src] + edge.weight)
      {
        d[id_dst] = d[id_src] + edge.weight;
        if (i < n)
          continue;

        d[id_dst] = -INF;
        is_negative_cycle = true;
      }
    }
  }

  if (!is_negative_cycle)
    return d;

  for (int i = 1; i < n; i++)
  {
    for (const auto &edge : g.edges)
    {
      const int id_src = edge.id_src;
      const int id_dst = edge.id_dst;
      if (d[id_src] == -INF && d[id_dst] != -INF)
        d[id_dst] = -INF;
    }
  }

  return d;
}

template <typename Weight>
vector<vector<Weight>> warshall_floyd(const Graph<Weight> &g, const Weight INF)
{
  const int n = g.size();
  vector<vector<Weight>> d(n, vector<Weight>(n, INF));
  for (size_t id = 0; id < n; id++)
    d[id][id] = 0;

  for (const auto &edge : g.edges)
    d[edge.id_src][edge.id_dst] = edge.weight;
  for (int id_new = 0; id_new < n; id_new++)
    for (int id_src = 0; id_src < n; id_src++)
      for (int id_dst = 0; id_dst < n; id_dst++)
        if (d[id_src][id_dst] > d[id_src][id_new] + d[id_new][id_dst])
          d[id_src][id_dst] = d[id_src][id_new] + d[id_new][id_dst];

  return d;
}

// ShortPath.h end------------------------------------------

void solve()
{
  using Weight = ll;
  int n, m;
  cin >> n >> m;
  vector<int> a(m), b(m);
  vector<Weight> cc(m);
  rep(j, m)
  {
    cin >> a[j] >> b[j] >> cc[j];
    a[j]--;
    b[j]--;
  }

  vector<vector<Weight>> in_i2costs(n), out_i2costs(n);
  rep(j, m)
  {
    out_i2costs[a[j]].push_back(cc[j]);
    in_i2costs[b[j]].push_back(cc[j]);
  }
  rep(v, n)
  {
    sort(all(in_i2costs[v]));
    sort(all(out_i2costs[v]));
  }

  map<int, int> vipc2k[300000][2][2];
  // map<int, int> vipc2k[30005][2][2];
  int cnt = 0;
  rep(v, n)
  {
    for (auto c : in_i2costs[v])
      vipc2k[v][0][0][c] = cnt++;
    for (auto c : in_i2costs[v])
      vipc2k[v][0][1][-c] = cnt++;
    for (auto c : out_i2costs[v])
      vipc2k[v][1][0][c] = cnt++;
    for (auto c : out_i2costs[v])
      vipc2k[v][1][1][-c] = cnt++;
  }
  int s = cnt, t = cnt + 1;
  Graph<Weight> g(cnt + 2);

  rep(v, n)
  {
    rep(p, 2)
    {
      // in to out
      for (auto [c, from] : vipc2k[v][0][p])
      {
        auto it = vipc2k[v][1][p].upper_bound(c);
        if (it == vipc2k[v][1][p].end())
          continue;
        int to = it->second;
        g.add_edge(from, to, 0);
      }

      // in to in, out to out
      for (auto it = vipc2k[v][1][p].begin(); it != vipc2k[v][1][p].end(); it++)
      {
        auto from = it->second;
        it++;
        if (it == vipc2k[v][1][p].end())
          break;
        auto to = it->second;
        it--;
        g.add_edge(from, to, 0);
      }
    }
  }

  rep(j, m) rep(p, 2)
  {
    Weight c = cc[j];
    auto from = vipc2k[a[j]][1][p][c * (p == 0 ? 1 : -1)];
    int np = p == 0 ? 1 : 0;
    auto to = vipc2k[b[j]][0][np][c * (np == 0 ? 1 : -1)];
    g.add_edge(from, to, c);
  }

  int v_start = 0, v_goal = n - 1;
  rep(pm, 2)
  {
    for (auto [c, to] : vipc2k[v_start][1][pm])
    {
      g.add_edge(s, to, 0);
    }
    for (auto [c, from] : vipc2k[v_goal][0][pm])
    {
      g.add_edge(from, t, 0);
    }
  }

  const ll INF = llinf - 1000000000000;
  auto dist = dijkstra(g, s, INF);
  if (dist[t] == INF)
  {
    cout << -1 << endl;
  }
  else
  {
    cout << dist[t] << endl;
  }

  // dbg(g);
  // rep(v, n) rep(io, 2) rep(pm, 2)
  // {
  //   cout << "v: " << v << (io == 0 ? " in" : " out") << (pm == 0 ? " + " : " - ") << vipc2k[v][io][pm] << endl;
  // }
}

int main()
{
  cin.tie(0);
  ios::sync_with_stdio(false);
  // cerr << "start" << endl;
  srand(time(0));
  cout << fixed << setprecision(15);

  solve();
  return 0;
}
accuracy: 1
time_ms: 900
memory_kb: 344616
final_rank: 13

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

//////////////////////////////   Begin Macros

#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define in(x, a, b) (a <= x and x < b)
#define rep(i, N) for (int i = 0; i < (int)(N); i++)
#define reprev(i, N) for (int i = (int)(N)-1; i >= 0; i--)
#define rep1(i, N) for (int i = 1; i <= (int)(N); i++)
#define rep1rev(i, N) for (int i = (int)(N); i >= 0; i--)
#define forbe(i, b, e) for (int i = (b); i < (e); i++)
#define forberev(i, b, e) for (int i = (e)-1; i >= (b); i--)
#define forfl(i, f, l) for (int i = (f); i <= (l); i++)
#define forflrev(i, f, l) for (int i = (l); i >= (f); i--)
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;

template <typename T>
bool chmax(T &m, const T q)
{
  if (m < q)
  {
    m = q;
    return true;
  }
  else
    return false;
}
template <typename T>
bool chmin(T &m, const T q)
{
  if (m > q)
  {
    m = q;
    return true;
  }
  else
    return false;
}
template <typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return {l.first + r.first, l.second + r.second}; }
template <typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return {l.first - r.first, l.second - r.second}; }
template <typename T>
pair<T, T> operator*(const pair<T, T> &l, const T &r) { return {l.first * r, l.second * r}; }
template <typename T>
pair<T, T> operator/(const pair<T, T> &l, const T &r) { return {l.first / r, l.second / r}; }
template <typename T>
istream &operator>>(istream &is, vector<T> &vec)
{
  for (auto &v : vec)
    is >> v;
  return is;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &vec)
{
  os << "[";
  for (auto v : vec)
    os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const deque<T> &vec)
{
  os << "deq[";
  for (auto v : vec)
    os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const set<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_set<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const multiset<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_multiset<T> &vec)
{
  os << "{";
  for (auto v : vec)
    os << v << ",";
  os << "}";
  return os;
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &pa)
{
  is >> pa.first >> pa.second;
  return is;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &pa)
{
  os << "(" << pa.first << "," << pa.second << ")";
  return os;
}
template <typename... Ts>
istream &operator>>(istream &is, tuple<Ts...> &theTuple)
{
  apply([&is](Ts &... tupleArgs) { ((is >> tupleArgs), ...); }, theTuple);
  return is;
}
template <typename... Ts>
ostream &operator<<(ostream &os, const tuple<Ts...> &theTuple)
{
  apply([&os](const Ts &... tupleArgs) {
    os << '(';
    size_t n(0);
    ((os << tupleArgs << (++n < sizeof...(Ts) ? "," : "")), ...);
    os << ')';
  },
        theTuple);
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const map<TK, TV> &mp)
{
  os << "{";
  for (auto v : mp)
    os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp)
{
  os << "{";
  for (auto v : mp)
    os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}

template <typename T>
void reset(vector<T> &v, const T reset_to)
{
  for (auto &x : v)
    x = reset_to;
}
inline int popcount(const unsigned int x) { return __builtin_popcount(x); }
// #define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << endl;

ll nC2(ll n)
{
  return n * (n - 1) / 2;
}

const int intinf = numeric_limits<int>::max();
const ll llinf = numeric_limits<ll>::max();
const pii udlr[4] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

//////////////////////////////   End Macros

// Graph.h start--------------------------------------------

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

template <typename Weight>
struct Vertex;
template <typename Weight>
struct Edge;

template <typename Weight>
struct Vertex
{
  int id;
  vector<int> ids_dst;
  vector<Edge<Weight>> edges;

  Vertex(const int id = 0) : id(id){};
  int &operator[](int n) { return ids_dst[n]; }
  const int &operator[](int n) const { return ids_dst[n]; }

  size_t size() const { return edges.size(); }
  void add_edge(const Edge<Weight> &);
};

template <typename Weight>
struct Edge
{
  int id_src, id_dst;
  Weight weight;

  Edge(const int id_src, const int id_dst) : id_src(id_src), id_dst(id_dst){};
  Edge(const int id_src, const int id_dst, const Weight weight) : id_src(id_src), id_dst(id_dst), weight(weight){};
};
template <typename Weight>
ostream &operator<<(ostream &os, const Edge<Weight> &e) { return os << "Edge(" << e.id_src << "->" << e.id_dst << "," << e.weight << ")"; }

template <typename Weight = long long>
struct Graph
{
  vector<Vertex<Weight>> vertices;
  vector<Edge<Weight>> edges;

  Graph(const int nvertices = 0);
  Vertex<Weight> &operator[](int n) { return vertices[n]; }
  const Vertex<Weight> &operator[](int n) const { return vertices[n]; }

  size_t size() const { return vertices.size(); }
  void add_edge(const Edge<Weight> &);
  void add_edge(const int id_src, const int id_dst) { add_edge({id_src, id_dst}); };
  void add_edge(const int id_src, const int id_dst, const Weight w) { add_edge({id_src, id_dst, w}); };
};
template <typename Weight>
ostream &operator<<(ostream &os, const Graph<Weight> &g)
{
  cout << "Graph(" << g.size() << ")"
       << "[" << endl;
  for (auto &e : g.edges)
    os << " " << e << "," << endl;
  cout << "]";
  return os;
}

//----------------------------------------------------------

template <typename Weight>
void Vertex<Weight>::add_edge(const Edge<Weight> &e)
{
  edges.push_back(e);
  ids_dst.push_back(e.id_dst);
}

template <typename Weight>
bool operator<(const Edge<Weight> &e1, const Edge<Weight> &e2)
{
  return e1.weight != e2.weight ? e1.weight > e2.weight : // !!INVERSE!!
             e1.id_src != e2.id_src ? e1.id_src < e2.id_src : e1.id_dst < e2.id_dst;
}

template <typename Weight>
Graph<Weight>::Graph(const int nvertices)
{
  for (int id = 0; id < nvertices; id++)
    vertices.emplace_back(id);
}
template <typename Weight>
void Graph<Weight>::add_edge(const Edge<Weight> &e)
{
  edges.push_back(e);
  vertices[e.id_src].add_edge(e);
}

template <typename Weight>
Graph<Weight> make_tree(Graph<Weight> &g)
{
  int nvertices = g.size();
  Graph<Weight> g_tree(nvertices);
  queue<int> q;
  vector<bool> is_used(nvertices, false);

  int v_start = 0;
  q.push(v_start);
  is_used[v_start] = true;
  while (!q.empty())
  {
    int v = q.front();
    q.pop();
    for (int c : g[v].ids_dst)
    {
      if (is_used[c])
        continue;
      g_tree.add_edge(v, c);
      g_tree.add_edge(c, v);
      q.push(c);
      is_used[c] = true;
    }
  }

  return g_tree;
}

// Graph.h end----------------------------------------------

// ShortPath.h start----------------------------------------

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

template <typename Weight>
vector<Weight> dijkstra(const Graph<Weight> &g, const int id_start, const Weight INF);
template <typename Weight>
vector<Weight> bellman_ford(const Graph<Weight> &g, const int id_start, const Weight INF);
template <typename Weight>
vector<vector<Weight>> warshall_floyd(const Graph<Weight> &g, const Weight INF);

//----------------------------------------------------------

template <typename Weight>
vector<Weight> dijkstra(const Graph<Weight> &g, const int id_start, const Weight INF)
{
  int n = g.size();
  using Pwi = pair<Weight, int>;
  vector<Weight> d(n, INF);
  d[id_start] = 0;
  vector<bool> is_used(n, false);
  priority_queue<Pwi, vector<Pwi>, greater<Pwi>> que;

  que.push(Pwi(0, id_start));
  while (!que.empty())
  {
    const int id_src = que.top().second; // que.top().first >= d[id_src]
    que.pop();

    if (is_used[id_src])
      continue;
    is_used[id_src] = true;

    for (const auto &edge : g.vertices[id_src].edges)
    {
      const int id_dst = edge.id_dst;
      if (d[id_dst] <= d[id_src] + edge.weight)
        continue;

      d[id_dst] = d[id_src] + edge.weight;
      que.push(Pwi(d[id_dst], id_dst));
    }
  }

  return d;
}

template <typename Weight>
vector<Weight> bellman_ford(const Graph<Weight> &g, const int id_start, const Weight INF)
{
  // INF�ɋC��t���� d_max < INF
  // ���̕H����A�N�Z�X�ł��钸�_�ɂ�d = -INF
  const int n = (int)g.vertices.size();
  vector<Weight> d(n, INF);
  d[id_start] = 0;
  bool is_negative_cycle = false;
  for (int i = 1; i <= n; i++)
  {
    for (const auto &edge : g.edges)
    {
      const int id_src = edge.id_src;
      const int id_dst = edge.id_dst;
      if (d[id_src] == INF)
        continue;

      if (d[id_dst] > d[id_src] + edge.weight)
      {
        d[id_dst] = d[id_src] + edge.weight;
        if (i < n)
          continue;

        d[id_dst] = -INF;
        is_negative_cycle = true;
      }
    }
  }

  if (!is_negative_cycle)
    return d;

  for (int i = 1; i < n; i++)
  {
    for (const auto &edge : g.edges)
    {
      const int id_src = edge.id_src;
      const int id_dst = edge.id_dst;
      if (d[id_src] == -INF && d[id_dst] != -INF)
        d[id_dst] = -INF;
    }
  }

  return d;
}

template <typename Weight>
vector<vector<Weight>> warshall_floyd(const Graph<Weight> &g, const Weight INF)
{
  const int n = g.size();
  vector<vector<Weight>> d(n, vector<Weight>(n, INF));
  for (size_t id = 0; id < n; id++)
    d[id][id] = 0;

  for (const auto &edge : g.edges)
    d[edge.id_src][edge.id_dst] = edge.weight;
  for (int id_new = 0; id_new < n; id_new++)
    for (int id_src = 0; id_src < n; id_src++)
      for (int id_dst = 0; id_dst < n; id_dst++)
        if (d[id_src][id_dst] > d[id_src][id_new] + d[id_new][id_dst])
          d[id_src][id_dst] = d[id_src][id_new] + d[id_new][id_dst];

  return d;
}

// ShortPath.h end------------------------------------------

map<int, int> vipc2k[300000][2][2];

void solve()
{
  using Weight = ll;
  int n, m;
  cin >> n >> m;
  vector<int> a(m), b(m);
  vector<Weight> cc(m);
  rep(j, m)
  {
    cin >> a[j] >> b[j] >> cc[j];
    a[j]--;
    b[j]--;
  }

  vector<vector<Weight>> in_i2costs(n), out_i2costs(n);
  rep(j, m)
  {
    out_i2costs[a[j]].push_back(cc[j]);
    in_i2costs[b[j]].push_back(cc[j]);
  }
  rep(v, n)
  {
    sort(all(in_i2costs[v]));
    sort(all(out_i2costs[v]));
  }

  // map<int, int> vipc2k[30005][2][2];
  int cnt = 0;
  rep(v, n)
  {
    for (auto c : in_i2costs[v])
      vipc2k[v][0][0][c] = cnt++;
    for (auto c : in_i2costs[v])
      vipc2k[v][0][1][-c] = cnt++;
    for (auto c : out_i2costs[v])
      vipc2k[v][1][0][c] = cnt++;
    for (auto c : out_i2costs[v])
      vipc2k[v][1][1][-c] = cnt++;
  }
  int s = cnt, t = cnt + 1;
  Graph<Weight> g(cnt + 2);

  rep(v, n)
  {
    rep(p, 2)
    {
      // in to out
      for (auto [c, from] : vipc2k[v][0][p])
      {
        auto it = vipc2k[v][1][p].upper_bound(c);
        if (it == vipc2k[v][1][p].end())
          continue;
        int to = it->second;
        g.add_edge(from, to, 0);
      }

      // in to in, out to out
      for (auto it = vipc2k[v][1][p].begin(); it != vipc2k[v][1][p].end(); it++)
      {
        auto from = it->second;
        it++;
        if (it == vipc2k[v][1][p].end())
          break;
        auto to = it->second;
        it--;
        g.add_edge(from, to, 0);
      }
    }
  }

  rep(j, m) rep(p, 2)
  {
    Weight c = cc[j];
    auto from = vipc2k[a[j]][1][p][c * (p == 0 ? 1 : -1)];
    int np = p == 0 ? 1 : 0;
    auto to = vipc2k[b[j]][0][np][c * (np == 0 ? 1 : -1)];
    g.add_edge(from, to, c);
  }

  int v_start = 0, v_goal = n - 1;
  rep(pm, 2)
  {
    for (auto [c, to] : vipc2k[v_start][1][pm])
    {
      g.add_edge(s, to, 0);
    }
    for (auto [c, from] : vipc2k[v_goal][0][pm])
    {
      g.add_edge(from, t, 0);
    }
  }

  const ll INF = llinf - 1000000000000;
  auto dist = dijkstra(g, s, INF);
  if (dist[t] == INF)
  {
    cout << -1 << endl;
  }
  else
  {
    cout << dist[t] << endl;
  }

  // dbg(g);
  // rep(v, n) rep(io, 2) rep(pm, 2)
  // {
  //   cout << "v: " << v << (io == 0 ? " in" : " out") << (pm == 0 ? " + " : " - ") << vipc2k[v][io][pm] << endl;
  // }
}

int main()
{
  cin.tie(0);
  ios::sync_with_stdio(false);
  // cerr << "start" << endl;
  srand(time(0));
  cout << fixed << setprecision(15);

  solve();
  return 0;
}
accuracy: 1
time_ms: 920
memory_kb: 341880
final_rank: 14

code_snippet: #include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <iomanip>
#include <set>
#include <tuple>
#define mkp make_pair
#define mkt make_tuple
#define rep(i,n) for(int i = 0; i < (n); ++i)
#define all(v) v.begin(),v.end()
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
template<class T> void chmin(T &a,const T &b){if(a>b) a=b;}
template<class T> void chmax(T &a,const T &b){if(a<b) a=b;}

typedef pair<ll,int> P;
typedef tuple<int,int,int,ll> TP;
const ll INF=1e18;

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N,M;
  cin>>N>>M;
  vector<int> A(M),B(M);
  vector<ll> C(M);
  rep(i,M) cin>>A[i]>>B[i]>>C[i];

  vector<vector<P>> in(N),out(N);
  vector<vector<ll>> inVals(N),outVals(N);
  rep(i,M){
    A[i]--;B[i]--;
    in[B[i]].push_back(mkp(C[i],A[i]));
    out[A[i]].push_back(mkp(C[i],B[i]));
    inVals[B[i]].push_back(C[i]);
    outVals[A[i]].push_back(C[i]);
  }
  rep(i,N){
    if(i==0){
      inVals[0].push_back(0);
      inVals[0].push_back(INF);
    }
    sort(all(inVals[i]));
    sort(all(outVals[i]));
    inVals[i].erase(unique(all(inVals[i])),inVals[i].end());
    outVals[i].erase(unique(all(outVals[i])),outVals[i].end());

    sort(all(in[i]));
    sort(all(out[i]));
  }


  vector<vector<vector<vector<TP>>>> g(N,vector<vector<vector<TP>>> (2));
  vector<vector<vector<ll>>> dist(N,vector<vector<ll>> (2));
  rep(i,N){
    g[i][0].resize((int)inVals[i].size());
    g[i][1].resize((int)inVals[i].size());
    dist[i][0].resize((int)inVals[i].size(),INF);
    dist[i][1].resize((int)inVals[i].size(),INF);

    {// next up
      for(int j=0;j<inVals[i].size();j++){
        ll val=inVals[i][j];
        ll endVal=INF;
        if(j+1<inVals[i].size()) endVal=inVals[i][j+1];

        int st=lower_bound(all(out[i]),mkp(val+1,-1))-out[i].begin();
        while(st<out[i].size()&&out[i][st].first<=endVal){
          int nex=out[i][st].second;
          ll cost=out[i][st].first;
          int tar=lower_bound(all(inVals[nex]),cost)-inVals[nex].begin();
          g[i][0][j].push_back(mkt(nex,1,tar,cost));
          st++;
        }
        if(j+1<inVals[i].size()) g[i][0][j].push_back(mkt(i,0,j+1,0));
      }
    }

    {// next down
      for(int j=0;j<inVals[i].size();j++){
        ll val=inVals[i][j];
        ll endVal=-1;
        if(j-1>=0) endVal=inVals[i][j-1];

        int st=lower_bound(all(out[i]),mkp(val,-1))-out[i].begin();
        st--;
        while(st>=0&&out[i][st].first>=endVal){
          int nex=out[i][st].second;
          ll cost=out[i][st].first;
          int tar=lower_bound(all(inVals[nex]),cost)-inVals[nex].begin();
          g[i][1][j].push_back(mkt(nex,0,tar,cost));
          st--;
        }
        if(j-1>=0) g[i][1][j].push_back(mkt(i,1,j-1,0));
      }
    }
  }

  typedef tuple<ll,int,int,int> TTP;
  priority_queue<TTP,vector<TTP>,greater<TTP>> PQ;
  rep(j,inVals[0].size()) rep(k,2){
    dist[0][k][j]=0;
    PQ.push(mkt(0,0,k,j));
  }

  ll answer=INF;
  while(!PQ.empty()){
    auto f=PQ.top();
    PQ.pop();

    int now=get<1>(f);
    int flag=get<2>(f);
    int pre=get<3>(f);
    ll d=get<0>(f);
    if(dist[now][flag][pre]<d) continue;
    if(now==N-1){
      answer=d;
      break;
    }

    for(auto &e:g[now][flag][pre]){
      int nex=get<0>(e);
      int nf=get<1>(e);
      int npre=get<2>(e);
      ll neco=get<3>(e);
      if(dist[nex][nf][npre]>d+neco){
        dist[nex][nf][npre]=d+neco;
        PQ.push(mkt(dist[nex][nf][npre],nex,nf,npre));
      }
    }
  }

  if(answer==INF) cout<<-1<<endl;
  else cout<<answer<<endl;


  return 0;
}
accuracy: 1
time_ms: 440
memory_kb: 175460
final_rank: 10

code_snippet: #include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <algorithm>
#include <array>
using namespace std;
using ll = long long;
ll inf = 1e15;

int main() {
    int N,M;
    scanf("%d%d",&N,&M);    
    vector<vector<pair<int,int>>> up_edge(N);
    vector<vector<pair<int,int>>> down_edge(N);
    vector<unordered_map<ll,ll>> dp_up(N); // 増加の辺でたどってきたとき
    vector<unordered_map<ll,ll>> dp_down(N); // 減少の辺でたどってきたとき
    int cnt=0;
    for(int i = 0; i < M; ++i) {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);    
        a--,b--;
        up_edge[a].emplace_back(c,b);
        down_edge[a].emplace_back(c,b);
        dp_up[b][c] = dp_down[b][c] = inf;
        if(b==N-1) cnt+=2;
    }
    //辺を先にソートしておく
    for(int i = 0; i < N; ++i) {
        sort(up_edge[i].begin(),up_edge[i].end());
        sort(down_edge[i].begin(),down_edge[i].end(),greater<pair<int,int>>());
    }

    using t = array<ll,4>; // コスト,直前重み,現在の頂点,直前が[増加:1, 減少:0]
    priority_queue<t,vector<t>,greater<t>> pq;
    pq.push({0,0,0,0});
    pq.push({0,inf,0,1});

    while(pq.size() && cnt){
        auto e = pq.top();
        pq.pop();
        //総コスト
        ll sum_cost  = e[0];
        //直前コスト
        ll prev_edge_cost = e[1];
        //現在の点
        int from     = e[2];
        //直前の状態[増加:1, 減少:0]
        int type     = e[3];

        //直前が増加の時
        if(type == 1) {
            while(down_edge[from].size()){
                auto p=down_edge[from].back();
                auto to = p.second;
                ll next_edge_cost = p.first;
                //次は小さくなる事(prev_edge_cost > next_edge_cost)が必須
                if(prev_edge_cost <= next_edge_cost) break; //辺に単調性があるので、無理ならbreak
                //最短距離なら更新
                if(dp_down[to][next_edge_cost] > sum_cost + next_edge_cost) {
                    dp_down[to][next_edge_cost] = sum_cost + next_edge_cost;
                    pq.push({sum_cost+next_edge_cost,next_edge_cost,to,!type});
                    if(to==N-1) cnt--;
                    if(!cnt) break;
                }
                down_edge[from].pop_back();
            }
        }
        //直前が減少の時
        if(type == 0) {
            while(up_edge[from].size()){
                auto p=up_edge[from].back();
                auto to = p.second;
                ll next_edge_cost = p.first;
                //次は大きくなる事(prev_edge_cost < next_edge_cost)が必須
                if(prev_edge_cost >= next_edge_cost) break; //辺に単調性があるので、無理ならbreak
                //最短距離なら更新
                if(dp_up[to][next_edge_cost] > sum_cost + next_edge_cost) {
                    dp_up[to][next_edge_cost] = sum_cost + next_edge_cost;
                    pq.push({sum_cost+next_edge_cost,next_edge_cost,to,!type});
                    if(to==N-1) cnt--;
                    if(!cnt) break;
                }
                up_edge[from].pop_back();
            }
        }
    }
    ll ans = inf;
    for(auto e:dp_up[N-1]) {
        ans = min(ans,e.second);
    }
    for(auto e:dp_down[N-1]) {
        ans = min(ans,e.second);
    }
    if(ans == inf) ans = -1;
    printf("%lld\n",ans);
    return 0;
}
accuracy: 1
time_ms: 360
memory_kb: 105984
final_rank: 6

code_snippet: //#define _GLIBCXX_DEBUG

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

#define endl '\n'
#define lfs cout<<fixed<<setprecision(10)
#define ALL(a)  (a).begin(),(a).end()
#define ALLR(a)  (a).rbegin(),(a).rend()
#define spa << " " <<
#define fi first
#define se second
#define MP make_pair
#define MT make_tuple
#define PB push_back
#define EB emplace_back
#define rep(i,n,m) for(ll i = (n); i < (ll)(m); i++)
#define rrep(i,n,m) for(ll i = (ll)(m) - 1; i >= (ll)(n); i--)
using ll = long long;
using ld = long double;
const ll MOD1 = 1e9+7;
const ll MOD9 = 998244353;
const ll INF = 1e18;
using P = pair<ll, ll>;
template<typename T1, typename T2>bool chmin(T1 &a,T2 b){if(a>b){a=b;return true;}else return false;}
template<typename T1, typename T2>bool chmax(T1 &a,T2 b){if(a<b){a=b;return true;}else return false;}
ll median(ll a,ll b, ll c){return a+b+c-max({a,b,c})-min({a,b,c});}
void ans1(bool x){if(x) cout<<"Yes"<<endl;else cout<<"No"<<endl;}
void ans2(bool x){if(x) cout<<"YES"<<endl;else cout<<"NO"<<endl;}
void ans3(bool x){if(x) cout<<"Yay!"<<endl;else cout<<":("<<endl;}
template<typename T1,typename T2>void ans(bool x,T1 y,T2 z){if(x)cout<<y<<endl;else cout<<z<<endl;}  
template<typename T>void debug(vector<vector<T>>&v,ll h,ll w){for(ll i=0;i<h;i++){cout<<v[i][0];for(ll j=1;j<w;j++)cout spa v[i][j];cout<<endl;}};
void debug(vector<string>&v,ll h,ll w){for(ll i=0;i<h;i++){for(ll j=0;j<w;j++)cout<<v[i][j];cout<<endl;}};
template<typename T>void debug(vector<T>&v,ll n){if(n!=0)cout<<v[0];for(ll i=1;i<n;i++)cout spa v[i];cout<<endl;};
template<typename T>vector<vector<T>>vec(ll x, ll y, T w){vector<vector<T>>v(x,vector<T>(y,w));return v;}
ll gcd(ll x,ll y){ll r;while(y!=0&&(r=x%y)!=0){x=y;y=r;}return y==0?x:y;}
vector<ll>dx={1,-1,0,0,1,1,-1,-1};vector<ll>dy={0,0,1,-1,1,-1,1,-1};
template<typename T>vector<T> make_v(size_t a,T b){return vector<T>(a,b);}
template<typename... Ts>auto make_v(size_t a,Ts... ts){return vector<decltype(make_v(ts...))>(a,make_v(ts...));}
template<typename T1, typename T2>ostream &operator<<(ostream &os, const pair<T1, T2>&p){return os << p.first << " " << p.second;}
template<typename T>ostream &operator<<(ostream &os, const vector<T> &v){for(auto &z:v)os << z << " ";cout<<"|"; return os;}
template<typename T>void rearrange(vector<ll>&ord, vector<T>&v){
  auto tmp = v;
  for(int i=0;i<tmp.size();i++)v[i] = tmp[ord[i]];
}
template<typename Head, typename... Tail>void rearrange(vector<ll>&ord,Head&& head, Tail&&... tail){
  rearrange(ord, head);
  rearrange(ord, tail...);
}
//mt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
int popcount(ll x){return __builtin_popcountll(x);};
int poplow(ll x){return __builtin_ctzll(x);};
int pophigh(ll x){return 63 - __builtin_clzll(x);};
struct edge {
  ll to,cost;
  edge(ll x,ll y):to(x),cost(y){};
};
vector<ll> dijkstra(vector<vector<edge>>&g,ll s = 0) {
    priority_queue<P, vector<P>, greater<P> > que;
    vector<ll>dist(g.size(),INF);
    dist[s] = 0;
    que.emplace(0, s);
    while (!que.empty()) {
        P p = que.top();
        que.pop();
        ll v = p.second;
        if (dist[v] < p.first) continue;
        for(auto e:g[v]) {
            if (dist[e.to] > dist[v] + e.cost) {
                dist[e.to] = dist[v] + e.cost;
                que.emplace(dist[e.to], e.to);
            }
        }
    }
    return dist;
}
int main(){
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  ll res=0,buf=0;
  bool judge = true;
  ll n,m;cin>>n>>m;
  vector<vector<P>>es(n);
  vector<vector<edge>>g(4*m+2);
  vector<ll>u(m),v(m),w(m);
  ll S=4*m,T=4*m+1;
  rep(i,0,m){
    cin>>u[i]>>v[i]>>w[i];u[i]--;v[i]--;
    es[u[i]].EB(w[i],2*i);
    es[v[i]].EB(w[i],2*i+1);
    if(u[i]==0){
      g[S].EB(2*i,0);
      g[S].EB(2*i+2*m,0);
    }
    if(v[i]==n-1){
      g[2*i].EB(T,w[i]);
      g[2*i+2*m].EB(T,w[i]);
    }
  }
  rep(i,0,n){
    sort(ALL(es[i]));
    //cout<<i<<endl;debug(es[i],es[i].size());
    rep(j,0,(ll)es[i].size()-1){
      g[es[i][j].se].EB(es[i][j+1].se,0);
      g[es[i][j+1].se+2*m].EB(es[i][j].se+2*m,0);
    }
  }
  rep(i,0,m){
    ll to=lower_bound(ALL(es[v[i]]),MP(w[i],INF))-es[v[i]].begin();
    //cout<<i spa to spa es[v[i]].size() spa es[v[i]][to].se spa w[i]<<endl;
    if(to<es[v[i]].size())g[2*i+2*m].EB(es[v[i]][to].se,w[i]);
    to=lower_bound(ALL(es[v[i]]),MP(w[i],-INF))-es[v[i]].begin();
    //cout<<i spa to spa es[v[i]].size()<<endl;
    if(to>0)g[2*i].EB(es[v[i]][to-1].se+2*m,w[i]);
  }
  auto dist=dijkstra(g,S);
  //cout<<dist[2*m+4]<<endl;
  //debug(dist,dist.size());
  ans(dist[T]==INF,-1,dist[T]);
  return 0;
}
accuracy: 1
time_ms: 340
memory_kb: 117836
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
const long long MOD=1000000007;
// const long long MOD=998244353;
#define LOCAL
#pragma region Macros
typedef long long ll;
typedef __int128_t i128;
typedef unsigned int uint;
typedef unsigned long long ull;
#define ALL(x) (x).begin(),(x).end()
const int INF=1e9;
const long long IINF=1e18;
const int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
const char dir[4]={'D','R','U','L'};

template<typename T>
istream &operator>>(istream &is,vector<T> &v){
    for (T &x:v) is >> x;
    return is;
}
template<typename T>
ostream &operator<<(ostream &os,const vector<T> &v){
    for (int i=0;i<v.size();++i){
        os << v[i] << (i+1==v.size()?"": " ");
    }
    return os;
}
template<typename T,typename U>
ostream &operator<<(ostream &os,const pair<T,U> &p){
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template<typename T,typename U,typename V>
ostream&operator<<(ostream &os,const tuple<T,U,V> &t){
    os << '(' << get<0>(t) << ',' << get<1>(t) << ',' << get<2>(t) << ')';
    return os;
}
template<typename T,typename U,typename V,typename W>
ostream&operator<<(ostream &os,const tuple<T,U,V,W> &t){
    os << '(' << get<0>(t) << ',' << get<1>(t) << ',' << get<2>(t) << ',' << get<3>(t) << ')';
    return os;
}
template<typename T,typename U>
ostream &operator<<(ostream &os,const map<T,U> &m){
    os << '{';
    for (auto itr=m.begin();itr!=m.end();){
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr!=m.end()) os << ',';
    }
    os << '}';
    return os;
}
template<typename T,typename U>
ostream &operator<<(ostream &os,const unordered_map<T,U> &m){
    os << '{';
    for (auto itr=m.begin();itr!=m.end();){
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr!=m.end()) os << ',';
    }
    os << '}';
    return os;
}
template<typename T>
ostream &operator<<(ostream &os,const set<T> &s){
    os << '{';
    for (auto itr=s.begin();itr!=s.end();){
        os << *itr;
        if (++itr!=s.end()) os << ',';
    }
    os << '}';
    return os;
}
template<typename T>
ostream &operator<<(ostream &os,const multiset<T> &s){
    os << '{';
    for (auto itr=s.begin();itr!=s.end();){
        os << *itr;
        if (++itr!=s.end()) os << ',';
    }
    os << '}';
    return os;
}
template<typename T>
ostream &operator<<(ostream &os,const unordered_set<T> &s){
    os << '{';
    for (auto itr=s.begin();itr!=s.end();){
        os << *itr;
        if (++itr!=s.end()) os << ',';
    }
    os << '}';
    return os;
}
template<typename T>
ostream &operator<<(ostream &os,const deque<T> &v){
    for (int i=0;i<v.size();++i){
        os << v[i] << (i+1==v.size()?"": " ");
    }
    return os;
}

void debug_out(){cerr << '\n';}
template<class Head,class... Tail>
void debug_out(Head&& head,Tail&&... tail){
    cerr << head;
    if (sizeof...(Tail)>0) cerr << ", ";
    debug_out(move(tail)...);
}
#ifdef LOCAL
#define debug(...) cerr << " ";\
cerr << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << '\n';\
cerr << " ";\
debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

template<typename T> T gcd(T x,T y){return y!=0?gcd(y,x%y):x;}
template<typename T> T lcm(T x,T y){return x/gcd(x,y)*y;}

template<class T1,class T2> inline bool chmin(T1 &a,T2 b){
    if (a>b){a=b; return true;} return false;
}
template<class T1,class T2> inline bool chmax(T1 &a,T2 b){
    if (a<b){a=b; return true;} return false;
}
#pragma endregion

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N,M; cin >> N >> M;
    struct edge{
        int u,w;
        edge(int u,int w):u(u),w(w){}
        bool operator<(const edge &rhs) const {return w<rhs.w;}
    };
    vector<vector<edge>> G(N);
    vector<vector<int>> ws(N);
    for (int i=0;i<M;++i){
        int a,b,c; cin >> a >> b >> c;
        G[--a].emplace_back(--b,c);
        ws[b].emplace_back(c);
    }
    ws[0].emplace_back(0);
    ws[0].emplace_back(INF);

    struct state{
        int w,id;
        state(int w,int id):w(w),id(id){}
    };

    vector<vector<state>> S(2*N);
    vector<unordered_map<int,int>> mp(N);
    int n=0;
    for (int i=0;i<N;++i){
        sort(ALL(G[i]));
        sort(ALL(ws[i]));
        for (int _=0;_<2;++_){
            for (int x:ws[i]){
                S[i+_*N].emplace_back(x,n++);
            }
        }
        for (int j=0;j<ws[i].size();++j){
            mp[i][ws[i][j]]=j;
        }
    }

    vector<vector<edge>> nG(n);
    for (int i=0;i<N;++i){
        for (int j=0;j+1<S[i].size();++j){
            nG[S[i][j].id].emplace_back(S[i][j+1].id,0);
        }
        for (int j=0;j+1<S[i+N].size();++j){
            nG[S[i+N][j+1].id].emplace_back(S[i+N][j].id,0);
        }
        int cur=0;
        for (auto e:G[i]){
            int u=e.u,w=e.w;
            while (cur+1<ws[i].size()&&ws[i][cur+1]<w) ++cur;
            if (0<=cur&&cur<ws[i].size()&&ws[i][cur]<w) nG[S[i][cur].id].emplace_back(S[u+N][mp[u][w]].id,w);
        }
        cur=ws[i].size()-1;
        for (int j=G[i].size()-1;j>=0;--j){
            auto e=G[i][j];
            int u=e.u,w=e.w;
            while (cur-1>=0&&ws[i][cur-1]>w) --cur;
            if (0<=cur&&cur<ws[i].size()&&ws[i][cur]>w) nG[S[i+N][cur].id].emplace_back(S[u][mp[u][w]].id,w);
        }
    }

    vector<ll> dp(n,IINF);
    priority_queue<pair<ll,int>> pq;
    dp[S[0].front().id]=0; pq.emplace(-dp[S[0].front().id],S[0].front().id);
    dp[S[N].back().id]=0; pq.emplace(-dp[S[N].back().id],S[N].back().id);

    while (!pq.empty()){
        auto p=pq.top(); pq.pop();
        int v=p.second;
        if (dp[v]<-p.first) continue;
        for (auto e:nG[v]){
            int u=e.u;
            if (chmin(dp[u],dp[v]+e.w)){
                pq.emplace(-dp[u],u);
            }
        }
    }

    ll ans=IINF;
    for (int _=0;_<2;++_){
        for (auto s:S[N-1+_*N]){
            chmin(ans,dp[s.id]);
        }
    }

    cout << (ans==IINF?-1:ans) << '\n';
}
accuracy: 1
time_ms: 300
memory_kb: 131636
final_rank: 5