Problem:
Problem J:
Round Trip
Jim is planning to visit one of his best friends in a town in the mountain area. First, he leaves his hometown and goes to the destination town. This is called the go phase. Then, he comes back to his hometown. This is called the return phase. You are expected to write a program to find the minimum total cost of this trip, which is the sum of the costs of the go phase and the return phase.
There is a network of towns including these two towns. Every road in this network is one-way, i.e., can only be used towards the specified direction. Each road requires a certain cost to travel.
In addition to the cost of roads, it is necessary to pay a specified fee to go through each town on the way. However, since this is the visa fee for the town, it is not necessary to pay the fee on the second or later visit to the same town.
The altitude (height) of each town is given. On the go phase, the use of descending roads is inhibited. That is, when going from town
a
to
b
, the altitude of
a
should not be greater than that of
b
. On the return phase, the use of ascending roads is inhibited in a similar manner. If the altitudes of
a
and
b
are equal, the road from
a
to
b
can be used on both phases.
Input
The input consists of multiple datasets, each in the following format.
n m
d
2
e
2
d
3
e
3
.
.
.
d
n-1
e
n-1
a
1
b
1
c
1
a
2
b
2
c
2
.
.
.
a
m
b
m
c
m
Every input item in a dataset is a non-negative integer. Input items in a line are separated by a space.
n
is the number of towns in the network.
m
is the number of (one-way) roads. You can assume the inequalities 2 ≤
n
≤ 50 and 0 ≤
m
≤
n
(
n
−1) hold. Towns are numbered from 1 to
n
, inclusive. The town 1 is Jim's hometown, and the town
n
is the destination town.
d
i
is the visa fee of the town
i
, and
e
i
is its altitude. You can assume 1 ≤
d
i
≤ 1000 and 1≤
e
i
≤ 999 for 2≤
i
≤
n
−1. The towns 1 and
n
do not impose visa fee. The altitude of the town 1 is 0, and that of the town n is 1000. Multiple towns may have the same altitude, but you can assume that there are no more than 10 towns with the same altitude.
The
j
-th road is from the town
a
j
to
b
j
with the cost
c
j
(1 ≤
j
≤
m
). You can assume 1 ≤
a
j
≤
n
, 1 ≤
b
j
≤
n
, and 1 ≤
c
j
≤ 1000. You can directly go from
a
j
to
b
j
, but not from
b
j
to
a
j
unless a road from
b
j
to
a
j
is separately given. There are no two roads connecting the same pair of towns towards the same direction, that is, for any
i
and
j
such that
i
≠
j
,
a
i
≠
a
j
or
b
i
≠
b
j
. There are no roads connecting a town to itself, that is, for any
j
,
a
j
≠
b
j
.
The last dataset is followed by a line containing two zeros (separated by a space).
Output
For each dataset in the input, a line containing the minimum total cost, including the visa fees, of the trip should be output. If such a trip is not possible, output “-1”.
Sample Input
3 6
3 1
1 2 1
2 3 1
3 2 1
2 1 1
1 3 4
3 1 4
3 6
5 1
1 2 1
2 3 1
3 2 1
2 1 1
1 3 4
3 1 4
4 5
3 1
3 1
1 2 5
2 3 5
3 4 5
4 2 5
3 1 5
2 1
2 1 
...(truncated)

Submitted solutions:

code_snippet: #include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<string>
using namespace std;
#define INF 199999999
#define eps 1e-8
int n,m;
struct node
{
    int en;
    int cost;
};
vector<node>g[55];
int fee[55];
int hig[55];
int dis[55][55];
int dis_go[55][55];
int dis_back[55][55];
long long v[55][55],v_go[55][55],v_back[55][55];
bool in[55];
long long pw[55];
void spfa1(int root,int dis[],long long v[])
{
    queue<int>q;
    q.push(root);
    for(int i=1;i<=n;i++)
    {
        dis[i]=INF;
        v[i]=0;
        in[i]=0;
    }
    in[root]=1;
    dis[root]=0;
    v[root]=pw[root];
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        in[now]=0;
        for(int i=0;i<g[now].size();i++)
        {
            int temp=g[now][i].en;
            if(hig[temp]<hig[now])  continue;
            if(dis[temp]>dis[now]+g[now][i].cost+fee[temp])
            {
                dis[temp]=dis[now]+g[now][i].cost+fee[temp];
                v[temp]=v[now]|pw[temp];
                if(!in[temp])
                {
                    q.push(temp);
                    in[temp]=1;
                }
            }
        }
    }
}
void spfa2(int root,int dis[],long long v[])
{
    queue<int>q;
    q.push(root);
    for(int i=1;i<=n;i++)
    {
        dis[i]=INF;
        v[i]=0;
        in[i]=0;
    }
    in[root]=1;
    dis[root]=0;
    v[root]=pw[root];
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        in[now]=0;
        for(int i=0;i<g[now].size();i++)
        {
            int temp=g[now][i].en;
            if(hig[temp]>hig[now])  continue;
            if(dis[temp]>dis[now]+g[now][i].cost+fee[temp])
            {
                dis[temp]=dis[now]+g[now][i].cost+fee[temp];
                v[temp]=v[now]|pw[temp];
                if(!in[temp])
                {
                    q.push(temp);
                    in[temp]=1;
                }
            }
        }
    }
}

void floyd()
{
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(k==i||i==j||k==j)    continue;
                int now=dis[i][k]+dis[k][j];
                long long now_v=v[i][k]&v[k][j];
                for(int l=1;l<=n;l++)
                    if(now_v&pw[l])    now-=fee[l];
                dis[i][j]=min(dis[i][j],now);
            }
        }
    }
    if(dis[1][n]<INF)   printf("%d\n",dis[1][n]);
    else printf("-1\n");
}
void ini()
{
    for(int i=1;i<=n;i++)   g[i].clear();
}
int main()
{
    pw[1]=1;
    for(int i=2;i<=50;i++)  pw[i]=pw[i-1]*2;
    while(1)
    {
        scanf("%d%d",&n,&m);
        ini();
        if(n==0&&m==0)  break;
        fee[1]=fee[n]=0;
        hig[1]=0;
        hig[n]=1000;
        for(int i=2;i<n;i++)    scanf("%d%d",fee+i,hig+i);
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            node temp;
            temp.en=b;
            temp.cost=c;
            g[a].push_back(temp);
        }
        for(int i=1;i<=n;i++)
        {
            spfa1(i,dis_go[i],v_go[i]);
            spfa2(i,dis_back[i],v_back[i]);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
            //    if(i==j)    continue;
                dis[i][j]=dis_go[i][j]+dis_back[j][i];
                v[i][j]=v_go[i][j]|v_back[j][i];
            }
        }
        floyd();
    }
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3640
final_rank: 3

code_snippet: #include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

const int INF = 1012345678;

struct city {
	int cost, height;
};

struct edge {
	int s, t, w;
};

struct state {
	int vs, vt, bit, d;
	bool operator<(const state& s) const {
		return d > s.d;
	}
};

int solve(int N, int M, const vector<city>& P, const vector<edge>& E) {
	// step #1. preparation
	vector<vector<edge> > G1(N), G2(N), G3(N), G4(N);
	for (edge e : E) {
		edge erev = edge{e.t, e.s, e.w};
		int h = P[e.t].height - P[e.s].height;
		if (h > 0) {
			G1[e.s].push_back(e);
		}
		if (h < 0) {
			G2[e.t].push_back(erev);
		}
		if (h == 0) {
			G3[e.s].push_back(e);
			G4[e.t].push_back(erev);
		}
	}
	vector<int> height_cnt(P[N - 1].height + 1, 0);
	vector<int> index(N, -1);
	for (int i = 0; i < N; i++) {
		index[i] = height_cnt[P[i].height]++;
	}
	int max_cnt = *max_element(height_cnt.begin(), height_cnt.end());

	// step #2. dijkstra: preparation
	priority_queue<state> que;
	vector<vector<vector<int> > > d(N, vector<vector<int> >(N, vector<int>(1 << max_cnt, INF)));
	auto push = [&](state z) -> void {
		if (P[z.vs].height <= P[z.vt].height) {
			if (!((z.bit >> index[z.vs]) & 1)) {
				z.bit |= 1 << index[z.vs];
				z.d += P[z.vs].cost;
			}
		}
		if (P[z.vs].height >= P[z.vt].height) {
			if (!((z.bit >> index[z.vt]) & 1)) {
				z.bit |= 1 << index[z.vt];
				z.d += P[z.vt].cost;
			}
		}
		if (d[z.vs][z.vt][z.bit] > z.d) {
			d[z.vs][z.vt][z.bit] = z.d;
			que.push(z);
		}
	};
	push(state{0, 0, 0, 0});

	// step #3. dijkstra: main
	while (!que.empty()) {
		state z = que.top();
		que.pop();
		if (d[z.vs][z.vt][z.bit] == z.d) {
			// case 1: move to the same height
			int base_h = P[z.vt].height - P[z.vs].height;
			if (base_h >= 0) {
				for (edge e : G3[z.vs]) {
					push(state{e.t, z.vt, z.bit, z.d + e.w});
				}
			}
			if (base_h <= 0) {
				for (edge e : G4[z.vt]) {
					push(state{z.vs, e.t, z.bit, z.d + e.w});
				}
			}

			// case 2: move to the new height
			if (base_h > 0) {
				for (edge e : G1[z.vs]) {
					push(state{e.t, z.vt, 0, z.d + e.w});
				}
			}
			if (base_h < 0) {
				for (edge e : G2[z.vt]) {
					push(state{z.vs, e.t, 0, z.d + e.w});
				}
			}
			if (base_h == 0) {
				for (edge e1 : G1[z.vs]) {
					for (edge e2 : G2[z.vt]) {
						push(state{e1.t, e2.t, 0, z.d + e1.w + e2.w});
					}
				}
			}
		}
	}

	// step #4. compute answer
	int ans = d[N - 1][N - 1][1];

	return ans;
}

int main() {
	while (true) {
		int N, M;
		cin >> N >> M;
		if (N == 0 && M == 0) {
			break;
		}
		vector<city> X(N);
		for (int i = 1; i < N - 1; i++) {
			cin >> X[i].cost >> X[i].height;
		}
		X[0] = city{0, 0};
		X[N - 1] = city{0, 1000};
		vector<edge> E(M);
		for (int i = 0; i < M; i++) {
			cin >> E[i].s >> E[i].t >> E[i].w;
			E[i].s--;
			E[i].t--;
		}
		int ans = solve(N, M, X, E);
		cout << (ans != INF ? ans : -1) << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 1270
memory_kb: 32596
final_rank: 14

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

struct City {
    int cost;
    int height;
};

int N; City T[59];
int M, C[59][59];
int dist_go[59][59];
int dist_ba[59][59];
int dp[59][59][59];
int dp2[59][59];
int kari_dp[59][59];

void Initialize() {
    for (int i = 0; i < 59; i++) {
        T[i].cost = 0; T[i].height = 0;
        for (int j = 0; j < 59; j++) {
            dist_go[i][j] = (1 << 29);
            dist_ba[i][j] = (1 << 29);
            C[i][j] = (1 << 29);
            dp2[i][j] = (1 << 29);
            kari_dp[i][j] = (1 << 29);
            for (int k = 0; k < 59; k++) dp[i][j][k] = (1 << 29);
        }
    }
}

int Solve() {
    Initialize();

    // Step 1. Input
    cin >> N >> M; if (N + M == 0) return -2;
    for (int i = 2; i <= N - 1; i++) cin >> T[i].cost >> T[i].height;
    for (int i = 1; i <= M; i++) {
        int a, b, c; cin >> a >> b >> c;
        C[a][b] = min(C[a][b], c);
    }
    T[1] = City{0, 0};
    T[N] = City{0, 1000};

    // Step 2. Compression
    vector<int> Zahyou;
    for (int i = 1; i <= N; i++) Zahyou.push_back(T[i].height);
    sort(Zahyou.begin(), Zahyou.end());
    Zahyou.erase(unique(Zahyou.begin(), Zahyou.end()), Zahyou.end());
    for (int i = 1; i <= N; i++) T[i].height = lower_bound(Zahyou.begin(), Zahyou.end(), T[i].height) - Zahyou.begin();

    // Step 3. DP Init
    dp[0][1][1] = 0;

    // Step 4. Get Shortest Distance
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (T[i].height <= T[j].height) dist_go[i][j] = C[i][j] + T[j].cost;
            if (T[j].height <= T[i].height) dist_ba[j][i] = C[i][j] + T[i].cost;
        }
    }
    for (int k = 1; k <= N; k++) {
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                dist_go[i][j] = min(dist_go[i][j], dist_go[i][k] + dist_go[k][j]);
                dist_ba[i][j] = min(dist_ba[i][j], dist_ba[i][k] + dist_ba[k][j]);
            }
        }
    }

    // Step 5. DP Main
    for (int h = 1; h < Zahyou.size(); h++) {
        vector<int> city_list;
        for (int i = 1; i <= N; i++) {
            if (T[i].height == h) city_list.push_back(i);
        }
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                dp[h][i][j] = min(dp[h][i][j], dp[h - 1][i][j]);
                for (int idx : city_list) {
                    dp[h][idx][j] = min(dp[h][idx][j], dp[h - 1][i][j] + dist_go[i][idx]);
                    dp[h][i][idx] = min(dp[h][i][idx], dp[h - 1][i][j] + dist_ba[j][idx]);
                }
            }
        }

        // Both Move
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) dp2[i][j] = (1 << 29);
        }
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                for (int idx_i : city_list) {
                    for (int idx_j : city_list) {
                        dp2[idx_i][idx_j] = min(dp2[idx_i][idx_j], dp[h - 1][i][j] + C[i][idx_i] + C[idx_j][j]);
                    }
                }
            }
        }
        /*cout << "dp2: h = " << h << endl;
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) printf("% 3d", min(99, dp2[i][j]));
            cout << endl;
        }
        cout << endl;
        cerr << "size = " << city_list.size() << endl;*/

        // Brute Force
        for (int mask = 0; mask < (1 << city_list.size()); mask++) {
            for (int i = 0; i < city_list.size(); i++) {
                for (int j = 0; j < city_list.size(); j++) {
                    kari_dp[city_list[i]][city_list[j]]  = (1 << 29);
                    if (!((mask >> i) & 1)) continue;
                    if (!((mask >> j) & 1)) continue;
                    kari_dp[city_list[i]][city_list[j]] = dp2[city_list[i]][city_list[j]];
                }
            }
            vector<int> mask_list;
            int visa_total = 0;
            for (int i = 0; i < city_list.size(); i++) {
                if ((mask >> i) & 1) {
                    mask_list.push_back(city_list[i]);
                    visa_total += T[city_list[i]].cost;
                }
            }
            for (int loops = 0; loops <= mask_list.size() * 2; loops++) {
                for (int i : mask_list) {
                    for (int j : mask_list) {
                        for (int k : mask_list) kari_dp[i][k] = min(kari_dp[i][k], kari_dp[i][j] + C[k][j]);
                        for (int k : mask_list) kari_dp[k][j] = min(kari_dp[k][j], kari_dp[i][j] + C[i][k]);
                    }
                }
            }
            for (int i : mask_list) {
                for (int j : mask_list) {
                    dp[h][i][j] = min(dp[h][i][j], kari_dp[i][j] + visa_total);
                }
            }
        }
    }

    /*for (int h = 0; h < Zahyou.size(); h++) {
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) printf("% 3d", min(99, dp[h][i][j]));
            cout << endl;
        }
        cout << endl;
    }*/

    // Return
    return (dp[Zahyou.size() - 1][N][N] == (1 << 29) ? -1 : dp[Zahyou.size() - 1][N][N]);
}

int main() {
    while (true) {
        int ret = Solve();
        if (ret == -2) break;
        cout << ret << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 4232
final_rank: 5

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

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

int main() {
while(1) {
    int N, M;
    cin >> N >> M;
    if (N == 0) return 0;
    vector<ll> Fee(N);
    vector<int> Alt(N);
    vector<int> Alts;
    Fee[0] = Fee[N-1] = 0, Alt[0] = 0, Alt[N-1] = 1000;
    rep(i,1,N-1) cin >> Fee[i] >> Alt[i];
    rep(i,0,N) Alts.push_back(Alt[i]);
    UNIQUE(Alts);
    rep(i,0,N) Alt[i] = LB(Alts, Alt[i]);
    int L = Alts.size();
    vector<vector<int>> City(L);
    rep(i,0,N) City[Alt[i]].push_back(i);
    vector<int> ID(N);
    rep(i,0,L) {
        rep(j,0,City[i].size()) {
            ID[City[i][j]] = j;
        }
    }
    vector<vector<pair<int,ll>>> G(N), H(N);
    rep(i,0,M) {
        int A, B;
        ll C;
        cin >> A >> B >> C;
        A--, B--;
        G[A].push_back({B,C});
        H[B].push_back({A,C});
    }
    vector DP(N, vector(N, vector<ll>(1<<10, INF)));
    DP[0][0][1] = 0;
    priority_queue<tuple<ll,int,int,int>, vector<tuple<ll,int,int,int>>, greater<tuple<ll,int,int,int>>> PQ;
    PQ.push({0,0,0,1});
    while(!PQ.empty()) {
        auto [d,i,j,k] = PQ.top();
        PQ.pop();
        if (d > DP[i][j][k]) continue;
        for (auto pi : G[i]) {
            auto [ni, nc] = pi;
            if (Alt[ni] > max(Alt[i], Alt[j])) {
                if (chmin(DP[ni][j][1<<ID[ni]], DP[i][j][k] + nc + Fee[ni])) {
                    PQ.push({DP[ni][j][1<<ID[ni]], ni, j, 1<<ID[ni]});
                }
            }
            if (Alt[ni] == max(Alt[i], Alt[j])) {
                if (chmin(DP[ni][j][k | (1<<ID[ni])], DP[i][j][k] + nc + ((k & (1<<ID[ni])) == 0 ? Fee[ni] : 0LL))) {
                    PQ.push({DP[ni][j][k | (1<<ID[ni])], ni, j, k | (1<<ID[ni])});
                }
            }
        }
        for (auto pj : H[j]) {
            auto [nj, nc] = pj;
            if (Alt[nj] > max(Alt[i], Alt[j])) {
                if (chmin(DP[i][nj][1<<ID[nj]], DP[i][j][k] + nc + Fee[nj])) {
                    PQ.push({DP[i][nj][1<<ID[nj]], i, nj, 1<<ID[nj]});
                }
            }
            if (Alt[nj] == max(Alt[i], Alt[j])) {
                if (chmin(DP[i][nj][k | (1<<ID[nj])], DP[i][j][k] + nc + ((k & (1<<ID[nj])) == 0 ? Fee[nj] : 0LL))) {
                    PQ.push({DP[i][nj][k | (1<<ID[nj])], i, nj, k | (1<<ID[nj])});
                }
            }
        }
    }
    ll ANS = INF;
    rep(i,0,1<<10) chmin(ANS, DP[N-1][N-1][i]);
    cout << (ANS == INF ? -1 : ANS) << endl;
}
}
accuracy: 1
time_ms: 1350
memory_kb: 60124
final_rank: 18

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

#define rep(i, n) for (int i = 0; i < (n); i++)
#define per(i, n) for (int i = (n)-1; i >= 0; i--)
#define rep2(i, l, r) for (int i = (l); i < (r); i++)
#define per2(i, l, r) for (int i = (r)-1; i >= (l); i--)
#define each(e, x) for (auto &e : x)
#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define eb emplace_back
#define MM << ' ' <<
#define TT template <typename T>
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

TT using minheap = priority_queue<T, vector<T>, greater<T>>;
TT using maxheap = priority_queue<T>;

TT void print(vector<T> v, T x = 0) {
    int n = sz(v);
    rep(i, n) cout << v[i] + x << (i == n - 1 ? '\n' : ' ');
    if (n == 0) cout << '\n';
}

TT void printn(vector<T> v, T x = 0) {
    int n = sz(v);
    rep(i, n) cout << v[i] + x << '\n';
}

TT void rearrange(vector<T> &v) {
    sort(all(v));
    v.erase(unique(all(v)), end(v));
}

TT int lb(vector<T> &v, T x) { return lower_bound(all(v), x) - begin(v); }
TT int ub(vector<T> &v, T x) { return upper_bound(all(v), x) - begin(v); }

const int inf = (1 << 30) - 1;
const ll INF = (1LL << 60) - 1;

struct io_setup {
    io_setup() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout << fixed << setprecision(15);
    }
} io_setup;

int main() {
    while (1) {
        int n, m;
        cin >> n >> m;
        if (!n)
            break;
        vector<int> d(n, 0), e(n, 0);
        e[n - 1] = 1000;
        rep2(i, 1, n - 1) cin >> d[i] >> e[i];
        vector<int> id(n), p(1001, 0);
        rep(i, n) id[i] = p[e[i]]++;
        vector<vector<pii>> g(n), rg(n);
        rep(i, m) {
            int a, b, c;
            cin >> a >> b >> c, a--, b--;
            g[a].eb(b, c);
            rg[b].eb(a, c);
        }
        const int inf = 1e9;
        vector dp(n, vector(n, vector(1 << 10, inf)));
        minheap<pair<int, pair<pii, int>>> que;
        auto upd = [&](int i, int j, int k, int nd) {
            if (chmin(dp[i][j][k], nd))
                que.emplace(nd, pair(pair(i, j), k));
        };
        upd(0, 0, 1, 0);
        bool ok = false;
        while (sz(que)) {
            auto [nd, ijk] = que.top();
            auto [ij, k] = ijk;
            auto [i, j] = ij;
            que.pop();
            if (nd != dp[i][j][k])
                continue;
            if (i == n - 1 && j == n - 1) {
                cout << nd << '\n';
                ok = true;
                break;
            }
            for (auto [ni, cost] : g[i]) {
                if (e[i] > e[ni])
                    continue;
                int nk = (e[ni] > max(e[i], e[j]) ? 0 : k);
                if (e[ni] != max(e[i], e[j]) || !(k >> id[ni] & 1))
                    cost += d[ni];
                if (e[ni] >= max(e[i], e[j])) nk |= 1 << id[ni];
                upd(ni, j, nk, nd + cost);
            }
            for (auto [nj, cost] : rg[j]) {
                if (e[j] > e[nj])
                    continue;
                int nk = (e[nj] > max(e[i], e[j]) ? 0 : k);
                if (e[nj] != max(e[i], e[j]) || !(k >> id[nj] & 1))
                    cost += d[nj];
                if (e[nj] >= max(e[i], e[j])) nk |= 1 << id[nj];
                upd(i, nj, nk, nd + cost);
            }
        }
        if (!ok)
            cout << -1 << '\n';
    }
}
accuracy: 1
time_ms: 660
memory_kb: 31816
final_rank: 12

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

const int INF = 1012345678;

struct city {
	int cost, height;
};

void warshall_floyd(int N, vector<vector<int> >& d) {
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			for (int k = 0; k < N; k++) {
				if (d[j][i] != INF && d[i][k] != INF) {
					d[j][k] = min(d[j][k], d[j][i] + d[i][k]);
				}
			}
		}
	}
}

int solve(int N, const vector<city>& C, const vector<vector<int> >& G) {
	// step #1. compute shortest path for up & down
	vector<vector<int> > d1(N, vector<int>(N, INF));
	vector<vector<int> > d2(N, vector<int>(N, INF));
	for (int i = 0; i < N; i++) {
		d1[i][i] = 0;
		d2[i][i] = 0;
	}
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (G[i][j] != INF) {
				if (C[i].height <= C[j].height) {
					d1[i][j] = G[i][j] + C[i].cost;
				}
				if (C[i].height >= C[j].height) {
					d2[i][j] = G[i][j] + C[j].cost;
				}
			}
		}
	}
	warshall_floyd(N, d1);
	warshall_floyd(N, d2);
	
	// step #2. dynamic programming
	vector<vector<int> > dp(N, vector<int>(N, INF)); // dp[i][j]: up = i, down = j
	dp[0][0] = 0;
	vector<int> hlist(N);
	for (int i = 0; i < N; i++) {
		hlist.push_back(C[i].height);
	}
	sort(hlist.begin(), hlist.end());
	hlist.erase(unique(hlist.begin(), hlist.end()), hlist.end());
	for (int h : hlist) {
		// case 1: same heights
		vector<int> plist;
		for (int i = 0; i < N; i++) {
			if (C[i].height == h) {
				plist.push_back(i);
			}
		}
		int S = plist.size();
		vector<vector<int> > ndp(S, vector<int>(S, INF));
		for (int i = 1; i < (1 << S); i++) {
			vector<int> splist, sid;
			int subcost = 0;
			for (int j = 0; j < S; j++) {
				if ((i >> j) & 1) {
					splist.push_back(plist[j]);
					sid.push_back(j);
					subcost += C[plist[j]].cost;
				}
			}
			int T = splist.size();
			vector<vector<int> > ds(T, vector<int>(T, INF));
			for (int j = 0; j < T; j++) {
				for (int k = 0; k < T; k++) {
					ds[j][k] = (j != k ? G[splist[j]][splist[k]] : 0);
				}
			}
			warshall_floyd(T, ds);
			for (int j = 0; j < T; j++) {
				for (int k = 0; k < T; k++) {
					if (dp[splist[j]][splist[k]] != INF) {
						for (int x = 0; x < T; x++) {
							for (int y = 0; y < T; y++) {
								if (ds[j][x] != INF && ds[y][k] != INF) {
									ndp[sid[x]][sid[y]] = min(ndp[sid[x]][sid[y]], dp[splist[j]][splist[k]] + ds[j][x] + ds[y][k] + subcost);
								}
							}
						}
					}
				}
			}
		}
		for (int j = 0; j < S; j++) {
			for (int k = 0; k < S; k++) {
				if (ndp[j][k] != INF) {
					dp[plist[j]][plist[k]] = min(dp[plist[j]][plist[k]], ndp[j][k] - C[plist[j]].cost - C[plist[k]].cost);
				}
			}
		}

		// case 2: different heights
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (C[i].height == h && dp[i][j] != INF) {
					for (int k = 0; k < N; k++) {
						if (d1[i][k] != INF) {
							dp[k][j] = min(dp[k][j], dp[i][j] + d1[i][k]);
						}
					}
				}
			}
		}
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (C[j].height == h && dp[i][j] != INF) {
					for (int k = 0; k < N; k++) {
						if (d2[k][j] != INF) {
							dp[i][k] = min(dp[i][k], dp[i][j] + d2[k][j]);
						}
					}
				}
			}
		}
	}

	return dp[N - 1][N - 1];
}

int main() {
	while (true) {
		int N, M;
		cin >> N >> M;
		if (N == 0 && M == 0) {
			break;
		}
		vector<city> C(N);
		for (int i = 1; i < N - 1; i++) {
			cin >> C[i].cost >> C[i].height;
		}
		C[0].height = 0;
		C[N - 1].height = 1000;
		vector<vector<int> > G(N, vector<int>(N, INF));
		for (int i = 0; i < M; i++) {
			int a, b, c;
			cin >> a >> b >> c;
			a -= 1;
			b -= 1;
			G[a][b] = min(G[a][b], c);
		}
		int ans = solve(N, C, G);
		cout << (ans != INF ? ans : -1) << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3416
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define foa(s, v) for(auto &s : v)
#define all(v) v.begin(), v.end()
#define REPname(a,b,c,d,...) d
#define rep(...) REPname(__VA_ARGS__, REP2, REP1, REP0)(__VA_ARGS__)
#define REP2(i,l,r) for(int i = l; i < r; i++)
#define REP1(i, x) REP2(i,0,x)
#define REP0(x) REP1(SPJ, x)
#define sz(x) int(x.size())

template <class T>
using V=vector<T>;

template <class T>
using VV=vector<V<T>>;

template<class T>
using pqmin = priority_queue<T, V<T>, greater<T>>;
using ll = long long ;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using vll = vector<ll>;
using vvll = V<vll>;
constexpr ll INF = 1e18;
constexpr int inf = 1e9;
template<class T>
inline bool chmax(T &a, T b){
	return a < b ? a=b, 1 : 0;
}
template <class T>
inline bool chmin(T &a, T b) {
	return a > b ? a = b, 1 : 0;
}


// template <c0lass T>
void view(ll x) {
	if(x > INF / 2) cerr << "INF";
	else cerr << x;
}


template <class T>
void view(T x) {
	cerr << x;
}

template <class T>
void view(V<T> v) {
	cerr << "{ ";
	foa(t, v) {view(t) ; cerr << ", ";}
	cerr << "}";
}


template <class T>
void view(VV<T> v) {
	cerr << "{ ";
	foa(t, v) {view(t) ; cerr << ",\n";}
	cerr << "}";
	cerr << endl;
}


// template <c0lass T>
void view(int x) {
	cerr << x;
}

#ifdef LOCAL
void debug_out() {}
template <class T>
void debug_out(T x) {
	view(x);
}
template <class H, class... T>
void debug_out(H h, T... t) {
	view(h);
	cerr << ", ";
	debug_out(t...);
}
#define debug(...)                                           \
	do {                                                     \
		cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                              \
		cerr << "]\n";                                       \
	} while(0)
#else
#define debug(...) (void(0))
#endif
using vvi = V<vi>;


ll solve(int n){
	int m; cin >> m;
	int hmax = 1001;
	vector<int> height(n);
	vector<ll> visa(n);
	vector<vi> towns(hmax);
	rep(i, 1, n - 1) {
		cin >> visa[i] >> height[i];
	}
	height.back() = hmax - 1;

	vector<int> order_height(n);
	iota(all(order_height), 0);
	sort(all(order_height), [&](int i, int j) { return height[i] < height[j]; });

	vector<int> mapsto(n);
	rep(i, n) mapsto[order_height[i]] = i;

	{
		vector<int> w(n);
		vector<ll> fee(n);
		rep(i, n) {
			int old = order_height[i];
			w[i] = height[old];
			fee[i] = visa[old];
		}
		swap(height, w);
		swap(fee, visa);
	}

	rep(i, n) {
		towns[height[i]].push_back(i);
	}

	vector<V<pair<int, ll>>> g(n), rg(n);
	rep(m) {
		int a, b;
		ll c; cin >> a >> b >> c;
		a--;
		b--;
		a = mapsto[a];
		b = mapsto[b];
		g[a].emplace_back(b, c);
		rg[b].emplace_back(a, c);
	}

	V<vector<vector<vector<vll>>>> pt(hmax);


	rep(h, hmax) {
		const auto & grp = towns[h];
		if(grp.empty()) continue;

		debug(grp);
		int mn = grp.front();
		int mx  = grp.back();
		int len = mx - mn + 1;
		vector<vector<vector<vll>>> pair_trans(len, vector(len, vector(len, vector<ll>(len, INF))));
		// from, from , to, to
		rep(i, len) rep(j, len) {
			ll c = visa[i + mn];
			if(i != j ) c += visa[j+mn];
			pair_trans[i][j][i][j] = c;
		}
		rep(use, (1 << len)) {
			vvll cost(len, vll(len, INF));
			ll visas = 0;
			rep(i, len) {
				if(!(use & (1 << i))) continue;
				cost[i][i] = 0;
				int from = i + mn;
				visas += visa[from];
				for(const auto& [to, ecost] : g[from]) {
					debug(from, to, ecost, mn, mx, use);
					if(mn <= to && to <= mx && (use & (1 << (to - mn)))) {
						debug(from, to, ecost);
						chmin(cost[i][to - mn], ecost);
					}
				}
			}
			rep(k, len) rep(i, len) rep(j, len) chmin(cost[i][j], cost.at(i).at(k) + cost.at(k).at(j));

			debug(use, cost);

			rep(i, len) rep(j, len) rep(k, len) rep(l, len) {
				chmin(pair_trans[i].at(j).at(k).at(l), cost[i][k] + cost[l][j] + visas);
			}
		}

		rep(i, len) rep(j, len) rep(k, len) rep(l, len) 
		{
			auto &t = pair_trans[i][j][k][l];
			if(t < INF / 2) debug(i, j, k, l, t);
		}

		pt[h] = pair_trans;
	}


	pqmin<tuple<ll, int, int>> q;
	q.emplace(0LL, 0, 0);
	vector<vector<ll>> dist(n, vll(n, INF));
	dist.front().front() = 0;

	while(q.size()) {
		ll d;
		int fth,bck;
		tie(d, fth, bck) = q.top();
		q.pop();
		if(fth == bck && bck == n - 1) return d;
		if(d > dist[fth].at(bck)) continue;

		debug(d, fth, bck);

		auto set_nxt = [&](int fnxt, int bnxt, ll val ) {
			if(val < 0) exit(1);
			if(chmin(dist.at(fnxt).at(bnxt), val)) {
				q.emplace(val, fnxt, bnxt);
			}
		};

		if(height[fth] == height[bck]) {
			auto& p = pt.at(height.at(fth));
			const int len = sz(p);
			const auto& current = towns[height[fth]];

			int fromf = fth - current.front();
			int fromb = bck - current.front();
			rep(i, len) rep(j, len) {
				int tof = current[i];
				int tob = current[j];
				ll cost = p[fromf].at(fromb).at(i).at(j) + d - visa[fth];
				if(fth != bck) cost -= visa[bck];
				debug(fth, bck, d, tof, tob, cost, p[fromf].at(fromb).at(i).at(j));
				set_nxt(tof, tob, cost);
			}
		}
		if(height[fth] <= height[bck]) {
			for(auto [nxt, ed_cost] : g[fth]) {
				if(height[nxt] >= height[fth]) {
					ll cost = d + ed_cost;
					if(nxt != bck) cost += visa[nxt];
					set_nxt(nxt, bck, cost);
				}
			}
		} else {
			for(auto [nxt, ed_cost] : rg[bck]) {
				if(height[nxt] >= height[bck]) {
					ll cost = d + ed_cost;
					if(nxt != fth) cost += visa[nxt];
					set_nxt(fth, nxt, cost);
				}
			}
		}
	}

	return -1;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout << fixed << setprecision(15);
	srand((unsigned)time(NULL));
	int n;
	while(cin >> n && n) cout << solve(n) << '\n';
}
accuracy: 1
time_ms: 140
memory_kb: 4388
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)
#define revrep(i, t, s) for (int i = (int)(t)-1; i >= (int)(s); --i)
#define all(x) begin(x), end(x)
template <typename T> bool chmax(T& a, const T& b) { return a < b ? (a = b, 1) : 0; }
template <typename T> bool chmin(T& a, const T& b) { return a > b ? (a = b, 1) : 0; }

template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int) v.size(); ++i) os << v[i] << " ";
    return os;
}

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

    while (true) {
        int n, m;
        cin >> n >> m;
        if (n == 0) break;
        vector<int> d(n), e(n);
        e[n-1] = 1000;
        vector<vector<int>> cities(1001);
        cities[0].push_back(0);
        cities[1000].push_back(n-1);
        rep(i,1,n-1) {
            cin >> d[i] >> e[i];
            cities[e[i]].push_back(i);
        }
        vector<vector<pair<int, int>>> G(n);
        rep(_,0,m) {
            int a, b, c;
            cin >> a >> b >> c;
            --a, --b;
            G[a].push_back({b, c});
        }

        vector<vector<int>> dp(n, vector<int>(n, 1e8));  // cost to go from i (up) to j (down)
        dp[n-1][n-1] = 0;

        revrep(a,1000,0) {
            int N = cities[a].size();
            rep(S,0,1<<N) {
                vector<vector<int>> up(n, vector<int>(n, 1e8)), down(n, vector<int>(n, 1e8));
                rep(i,0,n) up[i][i] = down[i][i] = 0;
                int dd = 0;
                rep(i,0,n) {
                    if (e[i] < a) continue;
                    if (e[i] == a) {
                        auto j = find(all(cities[a]), i) - cities[a].begin();
                        if (!(S>>j&1)) continue;
                        dd += d[i];
                    }
                    for (auto [j, c] : G[i]) {
                        if (e[i] <= e[j]) up[i][j] = c + d[i];
                        if (e[i] >= e[j]) down[i][j] = c + d[j];
                        if (e[i] == a) up[i][j] -= d[i];
                        if (e[j] == a) down[i][j] -= d[j];
                    }
                }

                rep(k,0,n) rep(i,0,n) rep(j,0,n) chmin(up[i][j], up[i][k] + up[k][j]);
                rep(k,0,n) rep(i,0,n) rep(j,0,n) chmin(down[i][j], down[i][k] + down[k][j]);

                for (int i : cities[a]) for (int j : cities[a]) {
                    int k = find(all(cities[a]), i) - cities[a].begin();
                    if (!(S>>k&1)) continue;
                    k = find(all(cities[a]), j) - cities[a].begin();
                    if (!(S>>k&1)) continue;

                    rep(k,0,n) rep(l,0,n) if (a < e[k] && a < e[l]) {
                        chmin(dp[i][j], up[i][k] + dp[k][l] + down[l][j] + dd);
                    }
                }
            }
        }
        cout << (dp[0][0] < 1e8 ? dp[0][0] : -1) << endl;
    }
}
accuracy: 1
time_ms: 3910
memory_kb: 3260
final_rank: 13

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

#ifdef _MSC_VER
#  include <intrin.h>
#else
#  include <x86intrin.h>
#endif

#include <limits>
#include <type_traits>

namespace suisen {
// ! utility
template <typename ...Types>
using constraints_t = std::enable_if_t<std::conjunction_v<Types...>, std::nullptr_t>;
template <bool cond_v, typename Then, typename OrElse>
constexpr decltype(auto) constexpr_if(Then&& then, OrElse&& or_else) {
	if constexpr (cond_v) {
		return std::forward<Then>(then);
	} else {
		return std::forward<OrElse>(or_else);
	}
}

// ! function
template <typename ReturnType, typename Callable, typename ...Args>
using is_same_as_invoke_result = std::is_same<std::invoke_result_t<Callable, Args...>, ReturnType>;
template <typename F, typename T>
using is_uni_op = is_same_as_invoke_result<T, F, T>;
template <typename F, typename T>
using is_bin_op = is_same_as_invoke_result<T, F, T, T>;

template <typename Comparator, typename T>
using is_comparator = std::is_same<std::invoke_result_t<Comparator, T, T>, bool>;

// ! integral
template <typename T, typename = constraints_t<std::is_integral<T>>>
constexpr int bit_num = std::numeric_limits<std::make_unsigned_t<T>>::digits;
template <typename T, unsigned int n>
struct is_nbit { static constexpr bool value = bit_num<T> == n; };
template <typename T, unsigned int n>
static constexpr bool is_nbit_v = is_nbit<T, n>::value;

// ?
template <typename T>
struct safely_multipliable {};
template <>
struct safely_multipliable<int> { using type = long long; };
template <>
struct safely_multipliable<long long> { using type = __int128_t; };
template <>
struct safely_multipliable<unsigned int> { using type = unsigned long long; };
template <>
struct safely_multipliable<unsigned long int> { using type = __uint128_t; };
template <>
struct safely_multipliable<unsigned long long> { using type = __uint128_t; };
template <>
struct safely_multipliable<float> { using type = float; };
template <>
struct safely_multipliable<double> { using type = double; };
template <>
struct safely_multipliable<long double> { using type = long double; };
template <typename T>
using safely_multipliable_t = typename safely_multipliable<T>::type;

template <typename T, typename = void>
struct rec_value_type {
	using type = T;
};
template <typename T>
struct rec_value_type<T, std::void_t<typename T::value_type>> {
	using type = typename rec_value_type<typename T::value_type>::type;
};
template <typename T>
using rec_value_type_t = typename rec_value_type<T>::type;

} // namespace suisen

// ! type aliases
using i128 = __int128_t;
using u128 = __uint128_t;

template <typename T>
using pq_greater = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <typename T, typename U>
using umap = std::unordered_map<T, U>;

// ! macros (capital: internal macro)
#define OVERLOAD2(_1,_2,name,...) name
#define OVERLOAD3(_1,_2,_3,name,...) name
#define OVERLOAD4(_1,_2,_3,_4,name,...) name

#define REP4(i,l,r,s)  for(std::remove_reference_t<std::remove_const_t<decltype(r)>>i=(l);i<(r);i+=(s))
#define REP3(i,l,r)	REP4(i,l,r,1)
#define REP2(i,n)	  REP3(i,0,n)
#define REPINF3(i,l,s) for(std::remove_reference_t<std::remove_const_t<decltype(l)>>i=(l);;i+=(s))
#define REPINF2(i,l)   REPINF3(i,l,1)
#define REPINF1(i)	 REPINF2(i,0)
#define RREP4(i,l,r,s) for(std::remove_reference_t<std::remove_const_t<decltype(r)>>i=(l)+fld((r)-(l)-1,s)*(s);i>=(l);i-=(s))
#define RREP3(i,l,r)   RREP4(i,l,r,1)
#define RREP2(i,n)	 RREP3(i,0,n)

#define rep(...)	OVERLOAD4(__VA_ARGS__, REP4   , REP3   , REP2   )(__VA_ARGS__)
#define rrep(...)   OVERLOAD4(__VA_ARGS__, RREP4  , RREP3  , RREP2  )(__VA_ARGS__)
#define repinf(...) OVERLOAD3(__VA_ARGS__, REPINF3, REPINF2, REPINF1)(__VA_ARGS__)

#define CAT_I(a, b) a##b
#define CAT(a, b) CAT_I(a, b)
#define UNIQVAR(tag) CAT(tag, __LINE__)
#define loop(n) for (std::remove_reference_t<std::remove_const_t<decltype(n)>> UNIQVAR(loop_variable) = n; UNIQVAR(loop_variable) --> 0;)

#define all(iterable) std::begin(iterable), std::end(iterable)
#define input(type, ...) type __VA_ARGS__; read(__VA_ARGS__)

#ifdef LOCAL
#  define debug(...) debug_internal(#__VA_ARGS__, __VA_ARGS__)

template <class T, class... Args>
void debug_internal(const char* s, T&& first, Args&&... args) {
	constexpr const char* prefix = "[\033[32mDEBUG\033[m] ";
	constexpr const char* open_brakets = sizeof...(args) == 0 ? "" : "(";
	constexpr const char* close_brakets = sizeof...(args) == 0 ? "" : ")";
	std::cerr << prefix << open_brakets << s << close_brakets << ": " << open_brakets << std::forward<T>(first);
	((std::cerr << ", " << std::forward<Args>(args)), ...);
	std::cerr << close_brakets << "\n";
}

#else
#  define debug(...) void(0)
#endif

// ! I/O utilities

// __int128_t
std::ostream& operator<<(std::ostream& dest, __int128_t value) {
	std::ostream::sentry s(dest);
	if (s) {
		__uint128_t tmp = value < 0 ? -value : value;
		char buffer[128];
		char* d = std::end(buffer);
		do {
			--d;
			*d = "0123456789"[tmp % 10];
			tmp /= 10;
		} while (tmp != 0);
		if (value < 0) {
			--d;
			*d = '-';
		}
		int len = std::end(buffer) - d;
		if (dest.rdbuf()->sputn(d, len) != len) {
			dest.setstate(std::ios_base::badbit);
		}
	}
	return dest;
}
// __uint128_t
std::ostream& operator<<(std::ostream& dest, __uint128_t value) {
	std::ostream::sentry s(dest);
	if (s) {
		char buffer[128];
		char* d = std::end(buffer);
		do {
			--d;
			*d = "0123456789"[value % 10];
			value /= 10;
		} while (value != 0);
		int len = std::end(buffer) - d;
		if (dest.rdbuf()->sputn(d, len) != len) {
			dest.setstate(std::ios_base::badbit);
		}
	}
	return dest;
}

// pair
template <typename T, typename U>
std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& a) {
	return out << a.first << ' ' << a.second;
}
// tuple
template <unsigned int N = 0, typename ...Args>
std::ostream& operator<<(std::ostream& out, const std::tuple<Args...>& a) {
	if constexpr (N >= std::tuple_size_v<std::tuple<Args...>>) {
		return out;
	} else {
		out << std::get<N>(a);
		if constexpr (N + 1 < std::tuple_size_v<std::tuple<Args...>>) {
			out << ' ';
		}
		return operator<<<N + 1>(out, a);
	}
}
// vector
template <typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& a) {
	for (auto it = a.begin(); it != a.end();) {
		out << *it;
		if (++it != a.end()) out << ' ';
	}
	return out;
}
// array
template <typename T, size_t N>
std::ostream& operator<<(std::ostream& out, const std::array<T, N>& a) {
	for (auto it = a.begin(); it != a.end();) {
		out << *it;
		if (++it != a.end()) out << ' ';
	}
	return out;
}
inline void print() { std::cout << '\n'; }
template <typename Head, typename... Tail>
inline void print(const Head& head, const Tail &...tails) {
	std::cout << head;
	if (sizeof...(tails)) std::cout << ' ';
	print(tails...);
}
template <typename Iterable>
auto print_all(const Iterable& v, std::string sep = " ", std::string end = "\n") -> decltype(std::cout << *v.begin(), void()) {
	for (auto it = v.begin(); it != v.end();) {
		std::cout << *it;
		if (++it != v.end()) std::cout << sep;
	}
	std::cout << end;
}

__int128_t parse_i128(std::string& s) {
	__int128_t ret = 0;
	for (int i = 0; i < int(s.size()); i++) if ('0' <= s[i] and s[i] <= '9') ret = 10 * ret + s[i] - '0';
	if (s[0] == '-') ret = -ret;
	return ret;
}
__uint128_t parse_u128(std::string& s) {
	__uint128_t ret = 0;
	for (int i = 0; i < int(s.size()); i++) if ('0' <= s[i] and s[i] <= '9') ret = 10 * ret + s[i] - '0';
	return ret;
}
// __int128_t
std::istream& operator>>(std::istream& in, __int128_t& v) {
	std::string s;
	in >> s;
	v = parse_i128(s);
	return in;
}
// __uint128_t
std::istream& operator>>(std::istream& in, __uint128_t& v) {
	std::string s;
	in >> s;
	v = parse_u128(s);
	return in;
}
// pair
template <typename T, typename U>
std::istream& operator>>(std::istream& in, std::pair<T, U>& a) {
	return in >> a.first >> a.second;
}
// tuple
template <unsigned int N = 0, typename ...Args>
std::istream& operator>>(std::istream& in, std::tuple<Args...>& a) {
	if constexpr (N >= std::tuple_size_v<std::tuple<Args...>>) {
		return in;
	} else {
		return operator>><N + 1>(in >> std::get<N>(a), a);
	}
}
// vector
template <typename T>
std::istream& operator>>(std::istream& in, std::vector<T>& a) {
	for (auto it = a.begin(); it != a.end(); ++it) in >> *it;
	return in;
}
// array
template <typename T, size_t N>
std::istream& operator>>(std::istream& in, std::array<T, N>& a) {
	for (auto it = a.begin(); it != a.end(); ++it) in >> *it;
	return in;
}
template <typename ...Args>
void read(Args &...args) {
	(std::cin >> ... >> args);
}

// ! integral utilities

// Returns pow(-1, n)
template <typename T>
constexpr inline int pow_m1(T n) {
	return -(n & 1) | 1;
}
// Returns pow(-1, n)
template <>
constexpr inline int pow_m1<bool>(bool n) {
	return -int(n) | 1;
}

// Returns floor(x / y)
template <typename T>
constexpr inline T fld(const T x, const T y) {
	return (x ^ y) >= 0 ? x / y : (x - (y + pow_m1(y >= 0))) / y;
}
template <typename T>
constexpr inline T cld(const T x, const T y) {
	return (x ^ y) <= 0 ? x / y : (x + (y + pow_m1(y >= 0))) / y;
}

template <typename T, suisen::constraints_t<suisen::is_nbit<T, 16>> = nullptr>
__attribute__((target("popcnt"))) constexpr inline int popcount(const T x) { return _mm_popcnt_u32(x); }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 32>> = nullptr>
__attribute__((target("popcnt"))) constexpr inline int popcount(const T x) { return _mm_popcnt_u32(x); }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 64>> = nullptr>
__attribute__((target("popcnt"))) constexpr inline int popcount(const T x) { return _mm_popcnt_u64(x); }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 16>> = nullptr>
constexpr inline int count_lz(const T x) { return x ? __builtin_clz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 32>> = nullptr>
constexpr inline int count_lz(const T x) { return x ? __builtin_clz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 64>> = nullptr>
constexpr inline int count_lz(const T x) { return x ? __builtin_clzll(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 16>> = nullptr>
constexpr inline int count_tz(const T x) { return x ? __builtin_ctz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 32>> = nullptr>
constexpr inline int count_tz(const T x) { return x ? __builtin_ctz(x) : suisen::bit_num<T>; }
template <typename T, suisen::constraints_t<suisen::is_nbit<T, 64>> = nullptr>
constexpr inline int count_tz(const T x) { return x ? __builtin_ctzll(x) : suisen::bit_num<T>; }
template <typename T>
constexpr inline int floor_log2(const T x) { return suisen::bit_num<T> -1 - count_lz(x); }
template <typename T>
constexpr inline int ceil_log2(const T x) { return floor_log2(x) + ((x & -x) != x); }
template <typename T>
constexpr inline int kth_bit(const T x, const unsigned int k) { return (x >> k) & 1; }
template <typename T>
constexpr inline int parity(const T x) { return popcount(x) & 1; }

// ! container

template <typename T, typename Comparator, suisen::constraints_t<suisen::is_comparator<Comparator, T>> = nullptr>
auto priqueue_comp(const Comparator comparator) {
	return std::priority_queue<T, std::vector<T>, Comparator>(comparator);
}

template <typename Iterable>
auto isize(const Iterable& iterable) -> decltype(int(iterable.size())) {
	return iterable.size();
}

template <typename T, typename Gen, suisen::constraints_t<suisen::is_same_as_invoke_result<T, Gen, int>> = nullptr>
auto generate_vector(int n, Gen generator) {
	std::vector<T> v(n);
	for (int i = 0; i < n; ++i) v[i] = generator(i);
	return v;
}
template <typename T>
auto generate_range_vector(T l, T r) {
	return generate_vector(r - l, [l](int i) { return l + i; });
}
template <typename T>
auto generate_range_vector(T n) {
	return generate_range_vector(0, n);
}

template <typename T>
void sort_unique_erase(std::vector<T>& a) {
	std::sort(a.begin(), a.end());
	a.erase(std::unique(a.begin(), a.end()), a.end());
}

template <typename InputIterator, typename BiConsumer>
auto foreach_adjacent_values(InputIterator first, InputIterator last, BiConsumer f) -> decltype(f(*first++, *last), void()) {
	if (first != last) for (auto itr = first, itl = itr++; itr != last; itl = itr++) f(*itl, *itr);
}
template <typename Container, typename BiConsumer>
auto foreach_adjacent_values(Container c, BiConsumer f) -> decltype(c.begin(), c.end(), void()) {
	foreach_adjacent_values(c.begin(), c.end(), f);
}

// ! other utilities

// x <- min(x, y). returns true iff `x` has chenged.
template <typename T>
inline bool chmin(T& x, const T& y) {
	if (y >= x) return false;
	x = y;
	return true;
}
// x <- max(x, y). returns true iff `x` has chenged.
template <typename T>
inline bool chmax(T& x, const T& y) {
	if (y <= x) return false;
	x = y;
	return true;
}

template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
std::string bin(T val, int bit_num = -1) {
	std::string res;
	if (bit_num >= 0) {
		for (int bit = bit_num; bit-- > 0;) res += '0' + ((val >> bit) & 1);
	} else {
		for (; val; val >>= 1) res += '0' + (val & 1);
		std::reverse(res.begin(), res.end());
	}
	return res;
}

template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
std::vector<T> digits_low_to_high(T val, T base = 10) {
	std::vector<T> res;
	for (; val; val /= base) res.push_back(val % base);
	if (res.empty()) res.push_back(T{ 0 });
	return res;
}
template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
std::vector<T> digits_high_to_low(T val, T base = 10) {
	auto res = digits_low_to_high(val, base);
	std::reverse(res.begin(), res.end());
	return res;
}

template <typename T>
std::string join(const std::vector<T>& v, const std::string& sep, const std::string& end) {
	std::ostringstream ss;
	for (auto it = v.begin(); it != v.end();) {
		ss << *it;
		if (++it != v.end()) ss << sep;
	}
	ss << end;
	return ss.str();
}

namespace suisen {}
using namespace suisen;
using namespace std;

struct io_setup {
	io_setup(int precision = 20) {
		std::ios::sync_with_stdio(false);
		std::cin.tie(nullptr);
		std::cout << std::fixed << std::setprecision(precision);
	}
} io_setup_ {};

// ! code from here

#include <algorithm>
#include <cassert>
#include <vector>

namespace suisen {
template <typename T>
class CoordinateCompressorBuilder {
	public:
		struct Compressor {
			public:
				static constexpr int absent = -1;

				// default constructor
				Compressor() : _xs(std::vector<T>{}) {}
				// Construct from strictly sorted vector
				Compressor(const std::vector<T> &xs) : _xs(xs) {
					assert(is_strictly_sorted(xs));
				}

				// Return the number of distinct keys.
				int size() const {
					return _xs.size();
				}
				// Check if the element is registered.
				bool has_key(const T &e) const {
					return std::binary_search(_xs.begin(), _xs.end(), e);
				}
				// Compress the element. if not registered, returns `default_value`. (default: Compressor::absent)
				int comp(const T &e, int default_value = absent) const {
					const int res = min_geq_index(e);
					return res != size() and _xs[res] == e ? res : default_value;
				}
				// Restore the element from the index.
				T decomp(const int compressed_index) const {
					return _xs[compressed_index];
				}
				// Compress the element. Equivalent to call `comp(e)`
				int operator[](const T &e) const {
					return comp(e);
				}
				// Return the minimum registered value greater than `e`. if not exists, return `default_value`.
				T min_gt(const T &e, const T &default_value) const {
					auto it = std::upper_bound(_xs.begin(), _xs.end(), e);
					return it == _xs.end() ? default_value : *it;
				}
				// Return the minimum registered value greater than or equal to `e`. if not exists, return `default_value`.
				T min_geq(const T &e, const T &default_value) const {
					auto it = std::lower_bound(_xs.begin(), _xs.end(), e);
					return it == _xs.end() ? default_value : *it;
				}
				// Return the maximum registered value less than `e`. if not exists, return `default_value`
				T max_lt(const T &e, const T &default_value) const {
					auto it = std::upper_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>());
					return it == _xs.rend() ? default_value : *it;
				}
				// Return the maximum registered value less than or equal to `e`. if not exists, return `default_value`
				T max_leq(const T &e, const T &default_value) const {
					auto it = std::lower_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>());
					return it == _xs.rend() ? default_value : *it;
				}
				// Return the compressed index of the minimum registered value greater than `e`. if not exists, return `compressor.size()`.
				int min_gt_index(const T &e) const {
					return std::upper_bound(_xs.begin(), _xs.end(), e) - _xs.begin();
				}
				// Return the compressed index of the minimum registered value greater than or equal to `e`. if not exists, return `compressor.size()`.
				int min_geq_index(const T &e) const {
					return std::lower_bound(_xs.begin(), _xs.end(), e) - _xs.begin();
				}
				// Return the compressed index of the maximum registered value less than `e`. if not exists, return -1.
				int max_lt_index(const T &e) const {
					return int(_xs.rend() - std::upper_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>())) - 1;
				}
				// Return the compressed index of the maximum registered value less than or equal to `e`. if not exists, return -1.
				int max_leq_index(const T &e) const {
					return int(_xs.rend() - std::lower_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>())) - 1;
				}
			private:
				std::vector<T> _xs;
				static bool is_strictly_sorted(const std::vector<T> &v) {
					return std::adjacent_find(v.begin(), v.end(), std::greater_equal<T>()) == v.end();
				}
		};
		CoordinateCompressorBuilder() : _xs(std::vector<T>{}) {}
		explicit CoordinateCompressorBuilder(const std::vector<T> &xs) : _xs(xs) {}
		explicit CoordinateCompressorBuilder(std::vector<T> &&xs) : _xs(std::move(xs)) {}
		template <typename Gen, constraints_t<is_same_as_invoke_result<T, Gen, int>> = nullptr>
		CoordinateCompressorBuilder(const int n, Gen generator) {
			reserve(n);
			for (int i = 0; i < n; ++i) push(generator(i));
		}
		// Attempt to preallocate enough memory for specified number of elements.
		void reserve(int n) {
			_xs.reserve(n);
		}
		// Add data.
		void push(const T &first) {
			_xs.push_back(first);
		}
		// Add data.
		void push(T &&first) {
			_xs.push_back(std::move(first));
		}
		// Add data in the range of [first, last). 
		template <typename Iterator>
		auto push(const Iterator &first, const Iterator &last) -> decltype(std::vector<T>{}.push_back(*first), void()) {
			for (auto it = first; it != last; ++it) _xs.push_back(*it);
		}
		// Add all data in the container. Equivalent to `push(iterable.begin(), iterable.end())`.
		template <typename Iterable>
		auto push(const Iterable &iterable) -> decltype(std::vector<T>{}.push_back(*iterable.begin()), void()) {
			push(iterable.begin(), iterable.end());
		}
		// Add data.
		template <typename ...Args>
		void emplace(Args &&...args) {
			_xs.emplace_back(std::forward<Args>(args)...);
		}
		// Build compressor.
		auto build() {
			std::sort(_xs.begin(), _xs.end()), _xs.erase(std::unique(_xs.begin(), _xs.end()), _xs.end());
			return Compressor {_xs};
		}
		// Build compressor from vector.
		static auto build(const std::vector<T> &xs) {
			return CoordinateCompressorBuilder(xs).build();
		}
		// Build compressor from vector.
		static auto build(std::vector<T> &&xs) {
			return CoordinateCompressorBuilder(std::move(xs)).build();
		}
		// Build compressor from generator.
		template <typename Gen, constraints_t<is_same_as_invoke_result<T, Gen, int>> = nullptr>
		static auto build(const int n, Gen generator) {
			return CoordinateCompressorBuilder<T>(n, generator).build();
		}
	private:
		std::vector<T> _xs;
};

} // namespace suisen

#ifdef _MSC_VER
#  include <intrin.h>
#else
#  include <x86intrin.h>
#endif

#include <cstdint>
#include <iostream>

namespace suisen {
	template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
	struct all_subset {
		struct all_subset_iter {
			const T s; T t;
			constexpr all_subset_iter(T s) : s(s), t(s + 1) {}
			constexpr auto operator*() const { return t; }
			constexpr auto operator++() {}
			constexpr auto operator!=(std::nullptr_t) { return t ? (--t &= s, true) : false; }
		};
		T s;
		constexpr all_subset(T s) : s(s) {}
		constexpr auto begin() { return all_subset_iter(s); }
		constexpr auto end() { return nullptr; }
	};

	// iterator over T s.t. T is subset of S and |T| = k
	struct all_subset_k {
		struct all_subset_k_iter {
			const uint32_t n, k, s;
			uint32_t t;
			__attribute__((target("avx2")))
			all_subset_k_iter(uint32_t s, uint32_t k) : n(uint32_t(1) << _mm_popcnt_u32(s)), k(k), s(s), t((uint32_t(1) << k) - 1) {}
			__attribute__((target("bmi2")))
			auto operator*() const { return _pdep_u32(t, s); }
			__attribute__((target("bmi")))
			auto operator++() {
				if (k == 0) {
					t = std::numeric_limits<uint32_t>::max();
				} else {
					uint32_t y = t + _blsi_u32(t); // t + (-t & t)
					t = y | ((y ^ t) >> _tzcnt_u32(t << 2));
				}
			}
			auto operator!=(std::nullptr_t) const { return t < n; }
		};
		uint32_t s, k;
		all_subset_k(uint32_t s, uint32_t k) : s(s), k(k) {
			assert(s != std::numeric_limits<uint32_t>::max());
		}
		auto begin() { return all_subset_k_iter(s, k); }
		auto end() { return nullptr; }
	};

	struct all_subset_k_64 {
		struct all_subset_k_iter_64 {
			const uint64_t n, s;
			const uint32_t k;
			uint64_t t;
			__attribute__((target("avx2")))
			all_subset_k_iter_64(uint64_t s, uint32_t k) : n(uint64_t(1) << _mm_popcnt_u64(s)), s(s), k(k), t((uint64_t(1) << k) - 1) {}
			__attribute__((target("bmi2")))
			auto operator*() const { return _pdep_u64(t, s); }
			__attribute__((target("bmi")))
			auto operator++() {
				if (k == 0) {
					t = std::numeric_limits<uint64_t>::max();
				} else {
					uint64_t y = t + _blsi_u64(t);
					t = y | ((y ^ t) >> _tzcnt_u64(t << 2));
				}
			}
			auto operator!=(std::nullptr_t) const { return t < n; }
		};
		uint64_t s;
		uint32_t k;
		all_subset_k_64(uint64_t s, uint32_t k) : s(s), k(k) {
			assert(s != std::numeric_limits<uint64_t>::max());
		}
		auto begin() { return all_subset_k_iter_64(s, k); }
		auto end() { return nullptr; }
	};

	struct all_setbit {
		struct all_setbit_iter {
			uint32_t s;
			all_setbit_iter(uint32_t s) : s(s) {}
			__attribute__((target("bmi")))
			auto operator*() { return _tzcnt_u32(s); }
			__attribute__((target("bmi")))
			auto operator++() { s = __blsr_u32(s); }
			auto operator!=(std::nullptr_t) { return s; }
		};
		uint32_t s;
		all_setbit(uint32_t s) : s(s) {}
		auto begin() { return all_setbit_iter(s); }
		auto end() { return nullptr; }
	};

	struct all_setbit_64 {
		struct all_setbit_iter_64 {
			uint64_t s;
			all_setbit_iter_64(uint64_t s) : s(s) {}
			__attribute__((target("bmi")))
			auto operator*() { return _tzcnt_u64(s); }
			__attribute__((target("bmi")))
			auto operator++() { s = __blsr_u64(s); }
			auto operator!=(std::nullptr_t) { return s; }
		};
		uint64_t s;
		all_setbit_64(uint64_t s) : s(s) {}
		auto begin() { return all_setbit_iter_64(s); }
		auto end() { return nullptr; }
	};
} // namespace suisen

void solve() {
	input(int, n, m);
	if (n == 0 and m == 0) exit(0);

	CoordinateCompressorBuilder<int> builder;

	vector<int> h(n), c(n);
	h[0] = 0, c[0] = 0;
	rep(i, 1, n - 1) read(c[i], h[i]);
	h[n - 1] = 1000, c[n - 1] = 0;

	rep(i, n) builder.push(h[i]);
	const auto cmp = builder.build();
	const int l = cmp.size();
	vector<long long> lev_sets(l);

	rep(i, n) {
		h[i] = cmp[h[i]];
		lev_sets[h[i]] |= 1LL << i;
	}

	vector g(l, vector<vector<pair<int, int>>>(n));
	vector rev_g(l, vector<vector<pair<int, int>>>(n));
	vector<vector<pair<int, int>>> asc(n), rev_dsc(n);
	loop(m) {
		input(int, u, v, w);
		--u, --v;
		if (h[u] < h[v]) {
			asc[u].emplace_back(v, w);
		} else if (h[u] > h[v]) {
			rev_dsc[v].emplace_back(u, w);
		} else {
			g[h[u]][u].emplace_back(v, w);
			rev_g[h[u]][v].emplace_back(u, w);
		}
	}

	static constexpr int inf = numeric_limits<int>::max() / 4;
	vector dp(l, vector(n, vector<int>(n, inf)));
	dp[0][0][0] = 0;
	rep(i, l - 1) {
		vector<vector<int>> dists(n);
		rep(j, n) if (kth_bit(lev_sets[i], j)) {
			vector<int> dist(n, inf);
			pq_greater<pair<int, int>> pq;
			pq.emplace(dist[j] = c[j], j);
			while (pq.size()) {
				auto [du, u] = pq.top();
				pq.pop();
				if (dist[u] != du) continue;
				for (auto [v, w] : g[i][u]) {
					if (chmin(dist[v], du + w + c[v])) {
						pq.emplace(dist[v], v);
					}
				}
			}
			dists[j].swap(dist);
		}
		vector<vector<int>> rev_dists(n);
		rep(k, n) if (kth_bit(lev_sets[i], k)) {
			vector<int> dist(n, inf);
			pq_greater<pair<int, int>> pq;
			pq.emplace(dist[k] = c[k], k);
			while (pq.size()) {
				auto [du, u] = pq.top();
				pq.pop();
				if (dist[u] != du) continue;
				for (auto [v, w] : rev_g[i][u]) {
					if (chmin(dist[v], du + w + c[v])) {
						pq.emplace(dist[v], v);
					}
				}
			}
			rev_dists[k].swap(dist);
		}

		CoordinateCompressorBuilder<int> builder_i;
		for (int v : all_setbit_64(lev_sets[i])) {
			builder_i.push(v);
		}
		const auto cmp_i = builder_i.build();
		const int siz = cmp_i.size();

		vector init_wf(siz, vector<int>(siz, inf));
		rep(cx, siz) init_wf[cx][cx] = 0;
		rep(cx, siz) for (auto [y, w] : g[i][cmp_i.decomp(cx)]) {
			init_wf[cx][cmp_i[y]] = w;
		}

		map<long long, vector<vector<int>>> wfs;
		for (auto s : all_subset(lev_sets[i])) {
			auto wf = init_wf;
			rep(cz, siz) if (kth_bit(s, cmp_i.decomp(cz))) {
				rep(cx, siz) if (kth_bit(s, cmp_i.decomp(cx))) {
					rep(cy, siz) if (kth_bit(s, cmp_i.decomp(cy))) {
						chmin(wf[cx][cy], wf[cx][cz] + wf[cz][cy]);
					}
				}
			}
			wfs[s] = move(wf);
		}

		rep(j, n) rep(k, n) {
			if (dp[i][j][k] == inf) continue;
			assert(h[j] >= i and h[k] >= i);

			if (kth_bit(lev_sets[i], j) and kth_bit(lev_sets[i], k)) {
				const int cj = cmp_i[j], ck = cmp_i[k];
				for (auto s : all_subset(lev_sets[i] & ~((1LL << j) | (1LL << k)))) {
					s |= 1LL << j, s |= 1LL << k;
					
					int fc = 0;
					for (int v : all_setbit_64(s)) fc += c[v];

					const auto &wf = wfs.at(s);
					for (auto x : all_setbit_64(s)) for (auto y : all_setbit_64(s)) {
						const int cx = cmp_i[x], cy = cmp_i[y];
						for (auto [nj, wj] : asc[x]) for (auto [nk, wk] : rev_dsc[y]) {
							chmin(dp[i + 1][nj][nk], dp[i][j][k] + wf[cj][cx] + wf[cy][ck] + fc + wj + wk);
						}
					}
				}
			} else if (kth_bit(lev_sets[i], j)) {
				rep(x, n) if (dists[j][x] != inf) {
					for (auto [nj, w] : asc[x]) {
						chmin(dp[i + 1][nj][k], dp[i][j][k] + dists[j][x] + w);
					}
				}
			} else if (kth_bit(lev_sets[i], k)) {
				rep(y, n) if (rev_dists[k][y] != inf) {
					for (auto [nk, w] : rev_dsc[y]) {
						chmin(dp[i + 1][j][nk], dp[i][j][k] + rev_dists[k][y] + w);
					}
				}
			} else {
				chmin(dp[i + 1][j][k], dp[i][j][k]);
			}
		}
	}

	print(dp[l - 1][n - 1][n - 1] == inf ? -1 : dp[l - 1][n - 1][n - 1]);
	// cout.flush();
}

int main() {
	while (true) solve();
	return 0;
}
accuracy: 1
time_ms: 4460
memory_kb: 4368
final_rank: 15

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

#define rep(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define ALL(v) (v).begin(),(v).end()
using ll=long long int;
const int inf = 0x3fffffff; const ll INF = 0x1fffffffffffffff; const double eps=1e-12;
template<typename T>inline bool chmax(T& a,T b){if(a<b){a=b;return 1;}return 0;}
template<typename T>inline bool chmin(T& a,T b){if(a>b){a=b;return 1;}return 0;}

void solve(){
    int n,m;
    cin>>n>>m;
    if(n==0)exit(0);
    vector<int> d(n),e(n);
    e[n-1]=1000;
    rep(i,1,n-1)cin>>d[i]>>e[i];
    int pos[n],ecnt[1010]={};
    rep(i,0,n)pos[i]=ecnt[e[i]]++;
    using P=array<int,2>;
    vector g(n,vector<P>()),rev(n,vector<P>());
    rep(_,0,m){
        int u,v,w;
        cin>>u>>v>>w;
        u--; v--;
        if(e[u]<=e[v])g[u].push_back({v,w});
        if(e[u]>=e[v])rev[v].push_back({u,w});
    }

    vector dp(n,vector(n,vector<ll>(1<<10,INF)));
    dp[0][0][1]=0;
    using T=pair<ll,array<int,3>>;
    priority_queue<T,vector<T>,greater<T>> pq;
    pq.push({0,{0,0,1}});

    auto insert=[&](int x,int y,int mask,ll dist)->void{
        if(chmin(dp[x][y][mask],dist)){
            pq.push({dp[x][y][mask],{x,y,mask}});
        }
    };

    while(!pq.empty()){
        auto [dist,state]=pq.top();
        pq.pop();
        auto [x,y,mask]=state;
        if(dp[x][y][mask]<dist)continue;
        for(auto& [nxt,add]:g[x]){
            if(e[nxt]<e[y])insert(nxt,y,mask,dist+add+d[nxt]);
            else if(e[nxt]==e[x] or e[nxt]==e[y])insert(nxt,y,mask|(1<<pos[nxt]),dist+add+(mask>>pos[nxt]&1?0:d[nxt]));
            else insert(nxt,y,1<<pos[nxt],dist+add+d[nxt]);
        }
        for(auto& [nxt,add]:rev[y]){
            if(e[nxt]<e[x])insert(x,nxt,mask,dist+add+d[nxt]);
            else if(e[nxt]==e[x] or e[nxt]==e[y])insert(x,nxt,mask|(1<<pos[nxt]),dist+add+(mask>>pos[nxt]&1?0:d[nxt]));
            else insert(x,nxt,1<<pos[nxt],dist+add+d[nxt]);
        }
    }
    ll ret=dp[n-1][n-1][1];
    if(ret==INF)puts("-1");
    else cout<<ret<<'\n';
}

int main(){
    for(;;)solve();
    return 0;
}
accuracy: 1
time_ms: 1540
memory_kb: 63500
final_rank: 19

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

using namespace std;

#define eps 1e-9
#define INF 2000000000              // 2e9
#define LLINF 2000000000000000000ll // 2e18 (llmax:9e18)
#define all(x) (x).begin(), (x).end()
#define sq(x) ((x) * (x))

#define rep(i, x) for (int i = 0; i < (int)(x); i++)
#define drep(i, x) for (int i = ((int)(x)-1); i >= 0; i--)

#define popcount __builtin_popcount
#define next __next
#define prev __prev

#ifndef LOCAL
#define dmp(...) ;
#else
#define dmp(...)                                                               \
  cerr << "[ " << #__VA_ARGS__ << " ] : " << dump_str(__VA_ARGS__) << endl
#endif

// ---------------- Utility ------------------

template <class T>
bool chmin(T &a, const T &b) {
  if (a <= b) return false;
  a = b;
  return true;
}

template <class T>
bool chmax(T &a, const T &b) {
  if (a >= b) return false;
  a = b;
  return true;
}

template <class T>
using MaxHeap = priority_queue<T>;

template <class T>
using MinHeap = priority_queue<T, vector<T>, greater<T>>;

template <class T>
vector<T> vect(int len, T elem) {
  return vector<T>(len, elem);
}

// ----------------- Input -------------------

template <class T, class U>
istream &operator>>(istream &is, pair<T, U> &p) {
  return is >> p.first >> p.second;
}

template <class T>
istream &operator>>(istream &is, vector<T> &vec) {
  for (int i = 0; i < vec.size(); i++) is >> vec[i];
  return is;
}

// ----------------- Output ------------------

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << p.first << ',' << p.second;
}

template <class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  for (const T &e : v) os << e << " ";
  return os;
}

template <class T>
ostream &operator<<(ostream &os, const deque<T> &d) {
  for (const T &e : d) os << e << " ";
  return os;
}

template <class T>
ostream &operator<<(ostream &os, const set<T> &s) {
  os << "{ ";
  for (const T &e : s) os << e << " ";
  return os << "}";
}

template <class T, class U>
ostream &operator<<(ostream &os, const map<T, U> &m) {
  os << "{ ";
  for (const auto &[key, val] : m) os << "( " << key << " -> " << val << " ) ";
  return os << "}";
}

template <class TupleTy, size_t... I>
void dump_tuple(ostream &os, const TupleTy t, std::index_sequence<I...>) {
  (..., (os << (I == 0 ? "" : ",") << std::get<I>(t)));
}

template <class... Args>
ostream &operator<<(ostream &os, const tuple<Args...> &t) {
  os << "(";
  dump_tuple(os, t, std::make_index_sequence<sizeof...(Args)>());
  return os << ")";
}

void dump_str_rec(ostringstream &) {}

template <class Head, class... Tail>
void dump_str_rec(ostringstream &oss, Head &&head, Tail &&... tail) {
  oss << ", " << head;
  dump_str_rec(oss, forward<Tail>(tail)...);
}

template <class T, class... U>
string dump_str(T &&arg, U &&... args) {
  ostringstream oss;
  oss << arg;
  dump_str_rec(oss, forward<U>(args)...);
  return oss.str();
}

// --------------- Fast I/O ------------------

void fastio() {
  cin.tie(0);
  ios::sync_with_stdio(0);
  cout << fixed << setprecision(20);
}

// ------------------ ACL --------------------

// #include <atcoder/modint>
// constexpr int MOD = 998244353;
// constexpr int MOD = 1000000007;
// using mint = atcoder::static_modint<MOD>;
// ostream &operator<<(ostream &os, const mint &v) {
//   return os << v.val();
// }

// ------------ End of template --------------

template <class Cost = int>
struct edge {
  int from, to;
  Cost cost;
  edge() {}
  edge(int from, int to, Cost cost) : from(from), to(to), cost(cost) {}

  // for debug
  friend ostream &operator<<(ostream &os, const edge &e) {
    os << e.from << " -> " << e.to << " : " << e.cost << ", ";
    return os;
  }
};

template <class Cost = int>
struct Graph {
  int V;
  vector<vector<edge<Cost>>> G;
  Graph() {}
  Graph(int V) : V(V) { G.resize(V); }
  void add_edge(int a, int b, Cost cost = Cost(0)) {
    G[a].push_back(edge<Cost>(a, b, cost));
  }
  void add_edge_undirected(int a, int b, Cost cost = Cost(0)) {
    G[a].push_back(edge<Cost>(a, b, cost));
    G[b].push_back(edge<Cost>(b, a, cost));
  }
  size_t size() const { return G.size(); }
  const vector<edge<Cost>> &operator[](int id) const { return G[id]; }

  // for debug
  friend ostream &operator<<(ostream &os, const Graph g) {
    for (int i = 0; i < g.size(); i++) {
      os << g[i];
      if (i + 1 < g.size()) os << endl;
    }
    return os;
  }
};

// verified
// https://atcoder.jp/contests/dwacon6th-final-open/submissions/10023433
template <class Cost>
vector<Cost> dijkstra(Graph<Cost> &g, int s) {
  assert(0 <= s && s < g.size());
  vector<Cost> dist;
  dist.assign(g.size(), numeric_limits<Cost>::max());
  dist[s] = Cost(0);
  MinHeap<pair<Cost, int>> q;
  q.push(make_pair(Cost(0), s));
  while (!q.empty()) {
    auto a = q.top();
    q.pop();
    int v = a.second;
    if (dist[v] < a.first) continue;
    for (auto e : g[v]) {
      if (dist[e.to] > dist[v] + e.cost) {
        dist[e.to] = dist[v] + e.cost;
        q.push(make_pair(dist[e.to], e.to));
      }
    }
  }
  return dist;
}

#define endl "\n"
using ll = long long;
using pii = pair<int, int>;

const bool multitest = false;

struct city {
  int h, fee, id, h_id;
  city() {}
  city(int h, int fee, int id, int h_id) : h(h), fee(fee), id(id), h_id(h_id) {}
  bool operator<(const city &c) const { return h < c.h; }
};

bool solve() {
  int n, m;
  cin >> n >> m;
  if (n == 0 && m == 0) return false;

  vector<city> cs(n, {0, 0, -1, -1});
  vector<int> h_cnt(1001, 0);
  for (int i = 1; i < n - 1; i++) {
    int d, e;
    cin >> d >> e;
    cs[i] = city(e, d, i, h_cnt[e]++);
  }
  cs[0] = city(0, 0, 0, 0), cs[n - 1] = city(1000, 0, n - 1, 0);
  h_cnt[0] = 1, h_cnt[1000] = 1;
  sort(all(cs));

  vector<int> rev(n, -1);
  for (int i = 0; i < n; i++) { rev[cs[i].id] = i; }

  dmp(rev);

  Graph<int> G(n), rG(n);
  for (int i = 0; i < m; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    a--;
    b--;
    a = rev[a], b = rev[b];
    if (cs[a].h <= cs[b].h) { G.add_edge(a, b, c); }
    if (cs[a].h >= cs[b].h) { rG.add_edge(b, a, c); }
  }

  // Graph<int> g(n * n * (1 << 10));

  auto encode = [&](int i, int j, int S) {
    return n * (1 << 10) * i + (1 << 10) * j + S;
  };

  auto decode = [&](int v, int &i, int &j, int &S) {
    S = v % (1 << 10), v /= (1 << 10);
    j = v % n, v /= n;
    i = v % n;
    return;
  };

  vector<int> dist;
  dist.assign(n * n * (1 << 10), INF);
  int s = encode(0, 0, 1);
  dist[s] = 0;

  MinHeap<pair<int, int>> q;
  q.push(make_pair(dist[s], s));

  auto update = [&](int u, int v, int cost) {
    if (dist[v] > dist[u] + cost) {
      dist[v] = dist[u] + cost;
      q.push(make_pair(dist[v], v));
    }
  };

  while (!q.empty()) {
    auto [d, u] = q.top();
    q.pop();
    if (dist[u] < d) continue;

    int i = -1, j = -1, S = -1;
    decode(u, i, j, S);

    if (cs[i].h <= cs[j].h) {
      for (auto e : G[i]) {
        int add = e.cost;
        int mask = (1 << cs[e.to].h_id);
        if (cs[e.to].h == cs[j].h) {
          if (!((S >> cs[e.to].h_id) & 1)) add += cs[e.to].fee;
          int v = encode(e.to, j, S | mask);
          update(u, v, add);
        } else if (cs[e.to].h > cs[j].h) {
          add += cs[e.to].fee;
          int v = encode(e.to, j, mask);
          update(u, v, add);
        } else {
          add += cs[e.to].fee;
          int v = encode(e.to, j, S);
          update(u, v, add);
        }
      }
    }

    if (cs[i].h >= cs[j].h) {
      for (auto e : rG[j]) {
        int add = e.cost;
        int mask = (1 << cs[e.to].h_id);
        if (cs[i].h == cs[e.to].h) {
          if (!((S >> cs[e.to].h_id) & 1)) add += cs[e.to].fee;
          int v = encode(i, e.to, S | mask);
          update(u, v, add);
        } else if (cs[e.to].h > cs[i].h) {
          add += cs[e.to].fee;
          int v = encode(i, e.to, mask);
          update(u, v, add);
        } else {
          add += cs[e.to].fee;
          int v = encode(i, e.to, S);
          update(u, v, add);
        }
      }
    }

    // for (auto e : g[v]) {
    //   if (dist[e.to] > dist[v] + e.cost) {
    //     dist[e.to] = dist[v] + e.cost;
    //     q.push(make_pair(dist[e.to], e.to));
    //   }
    // }
  }

  int ans = dist[encode(n - 1, n - 1, 1)];
  if (ans == INF)
    cout << -1 << endl;
  else
    cout << ans << endl;

  return true;
}

int main() {
  fastio();
  if (!multitest) {
    while (solve()) {}
  } else {
    cerr << "[Warning] Multi testcase mode on" << endl;
    int t;
    cin >> t;
    while (t--) solve();
  }
  return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 14988
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=55,INF=1<<29;

vector<pair<int,int>> G[MAX];
vector<pair<int,int>> rG[MAX];
int h[MAX];
int cost[MAX];
vector<int> pos[MAX];

int dp[MAX][MAX][1<<10];

int memo[MAX][MAX];

void init(int N){
    for(int i=0;i<N;i++){
        G[i].clear();
        rG[i].clear();
        pos[i].clear();
        h[i]=cost[i]=0;
        for(int j=0;j<N;j++) memo[i][j]=-1;
    }
    for(int i=0;i<=N;i++) for(int j=0;j<=N;j++) for(int k=0;k<(1<<10);k++) dp[i][j][k]=INF;
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N,M;cin>>N>>M;
        if(N==0&&M==0) break;
        init(N);
        
        h[0]=0;
        h[N-1]=1000;
        cost[0]=cost[N-1]=0;
        for(int i=1;i<N-1;i++){
            cin>>cost[i]>>h[i];
        }
        
        vector<int> useh(N);
        for(int i=0;i<N;i++) useh[i]=h[i];
        sort(all(useh));
        useh.erase(unique(all(useh)),useh.end());
        
        for(int i=0;i<N;i++){
            h[i]=lower_bound(all(useh),h[i])-useh.begin();
            pos[h[i]].push_back(i);
        }
        
        for(int i=0;i<M;i++){
            int a,b,c;cin>>a>>b>>c;
            a--;b--;
            G[a].push_back(mp(b,c));
            rG[b].push_back(mp(a,c));
        }
        
        dp[0][0][1]=0;
        
        auto p=[&](int hh,int id){
            if(memo[hh][id]!=-1) return memo[hh][id];
            for(int i=0;i<si(pos[hh]);i++){
                if(pos[hh][i]==id) return memo[hh][id]=i;
            }
            return -1;
        };
        
        for(int t=0;t<N;t++){
            for(int i=0;i<N;i++){
                for(int j=0;j<N;j++){
                    int z;
                    if(h[i]>=h[j]) z=si(pos[h[i]]);
                    else z=si(pos[h[j]]);
                    for(int k=0;k<(1<<z);k++){
                        if(dp[i][j][k]==INF) continue;
                        
                        for(auto to:G[i]){
                            if(h[i]>h[to.fi]) continue;
                            if(h[i]==h[j]){
                                if(h[i]==h[to.fi]){
                                    int x=p(h[i],to.fi);
                                    if(k&(1<<x)){
                                        chmin(dp[to.fi][j][k],dp[i][j][k]+to.se);
                                    }else{
                                        chmin(dp[to.fi][j][k|(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                    }
                                }else{
                                    int x=p(h[to.fi],to.fi);
                                    chmin(dp[to.fi][j][(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                }
                            }else if(h[i]>h[j]){
                                int x=p(h[to.fi],to.fi);
                                chmin(dp[to.fi][j][(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                            }else{
                                if(h[j]==h[to.fi]){
                                    int x=p(h[j],to.fi);
                                    if(k&(1<<x)){
                                        chmin(dp[to.fi][j][k],dp[i][j][k]+to.se);
                                    }else{
                                        chmin(dp[to.fi][j][k|(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                    }
                                }else{
                                    int x=p(h[to.fi],to.fi);
                                    chmin(dp[to.fi][j][(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                }
                            }
                        }
                        
                        for(auto to:rG[j]){
                            if(h[i]>h[to.fi]) continue;
                            if(h[i]==h[j]){
                                if(h[j]==h[to.fi]){
                                    int x=p(h[j],to.fi);
                                    if(k&(1<<x)){
                                        chmin(dp[i][to.fi][k],dp[i][j][k]+to.se);
                                    }else{
                                        chmin(dp[i][to.fi][k|(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                    }
                                }else{
                                    int x=p(h[to.fi],to.fi);
                                    chmin(dp[i][to.fi][(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                }
                            }else if(h[j]>h[i]){
                                int x=p(h[to.fi],to.fi);
                                chmin(dp[i][to.fi][(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                            }else{
                                if(h[i]==h[to.fi]){
                                    int x=p(h[i],to.fi);
                                    if(k&(1<<x)){
                                        chmin(dp[i][to.fi][k],dp[i][j][k]+to.se);
                                    }else{
                                        chmin(dp[i][to.fi][k|(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                    }
                                }else{
                                    int x=p(h[to.fi],to.fi);
                                    chmin(dp[i][to.fi][(1<<x)],dp[i][j][k]+to.se+cost[to.fi]);
                                }
                            }
                        }
                    }
                }
            }
        }
        
        int ans=INF;
        
        for(int k=0;k<(1<<10);k++) chmin(ans,dp[N-1][N-1][k]);
        
        if(ans==INF) ans=-1;
        
        cout<<ans<<"\n";
        
    }
}
accuracy: 1
time_ms: 6750
memory_kb: 14624
final_rank: 20

code_snippet: #include"bits/stdc++.h"
using namespace std;
#define ALL(x) begin(x),end(x)
#define rep(i,n) for(int i=0;i<(n);i++)
#define debug(v) cout<<#v<<":";for(auto x:v){cout<<x<<' ';}cout<<endl;
#define mod 998244353
using ll=long long;
const int INF=10000000;
const ll LINF=1001002003004005006ll;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
template<class T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<class T>bool chmin(T &a,const T &b){if(b<a){a=b;return true;}return false;}

struct IOSetup{
    IOSetup(){
        cin.tie(0);
        ios::sync_with_stdio(0);
        cout<<fixed<<setprecision(12);
    }
} iosetup;
 
template<typename T>
ostream &operator<<(ostream &os,const vector<T>&v){
    for(int i=0;i<(int)v.size();i++) os<<v[i]<<(i+1==(int)v.size()?"":" ");
    return os;
}
template<typename T>
istream &operator>>(istream &is,vector<T>&v){
    for(T &x:v)is>>x;
    return is;
}

int N,M;

using P=pair<int,int>;
using PP=pair<int,P>;

/*
高い場所に１移動する場合
逐一，同じ移動先に移動するならコストを1回しか支払わないようにしながらDijkstraをすれば良い
同じ高さの移動のみ両者の移動がトポロジカルソート順になるとは限らない
ここは位置のスワップコストを求めてやれば良い．
d[i][j] -> d[j][i]とする場合のコスト
この際，i, jのvisa feeは一度だけ支払えば良い

到達時にvisa feeを支払いつつdijkstraをすることを考える．
同じ高さで(i,j) -> (j,i)に移動するときに，お互い，visa feeを支払わずに移動してよいとする．
なぜならiがiに到達する時点でiのvisa feeを支払済であり，jに関しても同じことが言えるためである
また，このようなswapコストを定義する理由としては，同じ高さでの移動に関しては行きはa-b-cの順序で移動するが，
帰りと逆順ではc-b-aで移動している可能性がある(両者の移動順序がトポソ不可)ため，
d[a][c]->d[b][b]->d[c][a]という遷移だと，a,cのvisa feeをそれぞれ二度支払いそうになる．
よって同じ高さでのswap costを用意してやるとうまい．

天才か？
*/

void solve(){
    vector<int> D(N),E(N);// visa fee, altitude
    D[0]=0, D[N-1]=0;
    E[0]=0, E[N-1]=INF;
    for(int i=1;i<N-1;i++) cin>>D[i]>>E[i];

    vector<vector<int>> C(N,vector<int>(N,INF));
    rep(i,N) C[i][i]=0;
    rep(i,M){
        int u,v,c;cin>>u>>v>>c;u--,v--;
        chmin(C[u][v],c);
    }

    vector<vector<int>> sw(N,vector<int>(N,INF));// 同じ高さの場合のみDAGではなくなる．行きと帰りで位置をswapするコスト
    rep(i,N){
        priority_queue<P,vector<P>,greater<P>> que;

        sw[i][i]=0;
        que.emplace(0, i);

        while(!que.empty()){
            auto [d, cur]=que.top();que.pop();
            if(d<sw[i][cur]) continue;

            rep(j,N)if(i!=j and E[i]==E[j]){
                if(chmin(sw[i][j], d+C[cur][j]*2+D[j])) que.emplace(sw[i][j], j);// ここもD[j]の支払いは一度で良い
            }
        }
        rep(j,N)if(i!=j) sw[i][j]-=D[j];// i, jもうコスト支払済なのでいい
    }

    priority_queue<PP,vector<PP>,greater<PP>> que;
    vector<vector<int>> res(N,vector<int>(N, INF));

    res[0][0]=0;
    que.emplace(res[0][0], make_pair(0,0));
    while(!que.empty()){
        auto pp=que.top();que.pop();
        int d=pp.first;
        int i,j;
        tie(i,j)=pp.second;

        if(res[i][j]<d) continue;
        
        // step - i
        rep(k,N)if(E[k]>=E[i]){
            if(chmin(res[k][j], d+C[i][k]+D[k])) que.emplace(res[k][j],make_pair(k,j));
        }

        // step - j
        rep(k,N)if(E[k]>=E[j]){
            if(chmin(res[i][k], d+C[k][j]+D[k])) que.emplace(res[i][k],make_pair(i,k));
        }

        // swap
        if(i!=j and E[i]==E[j]){
            if(chmin(res[j][i], d+sw[i][j])) que.emplace(res[j][i],make_pair(j,i));
        }

        // i -> k and j-> k
        rep(k,N)if(E[k]>=E[i] and E[k]>=E[j]){
            if(chmin(res[k][k], d+D[k]+C[i][k]+C[k][j])) que.emplace(res[k][k], make_pair(k,k));
        }
    }
    if(res[N-1][N-1]<INF) cout<<res[N-1][N-1]<<endl;
    else                  cout<<-1<<endl;
    return ;
}

signed main(){
    while(cin>>N>>M, N or M) solve();
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3672
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int INF = 10000000;
int main(){
  while (true){
    int n, m;
    cin >> n >> m;
    if (n == 0 && m == 0){
      break;
    }
    vector<int> d(n), e(n);
    d[0] = 0;
    e[0] = 0;
    for (int i = 1; i < n - 1; i++){
      cin >> d[i] >> e[i];
    }
    d[n - 1] = 0;
    e[n - 1] = 1000;
    vector<vector<int>> E(n, vector<int>(n, INF));
    for (int i = 0; i < n; i++){
      E[i][i] = 0;
    }
    for (int i = 0; i < m; i++){
      int a, b, c;
      cin >> a >> b >> c;
      a--;
      b--;
      E[a][b] = c;
    }
    vector<int> e2 = e;
    sort(e2.begin(), e2.end());
    e2.erase(unique(e2.begin(), e2.end()), e2.end());
    int h = e2.size();
    for (int i = 0; i < n; i++){
      e[i] = lower_bound(e2.begin(), e2.end(), e[i]) - e2.begin();
    }
    vector<vector<int>> id(h);
    for (int i = 0; i < n; i++){
      id[e[i]].push_back(i);
    }
    vector<vector<vector<vector<int>>>> dp(n, vector<vector<vector<int>>>(n, vector<vector<int>>(n, vector<int>(n, INF))));
    for (int i = 0; i < h; i++){
      int cnt = id[i].size();
      for (int j = 0; j < (1 << cnt); j++){
        vector<int> id2;
        int sum = 0;
        for (int k = 0; k < cnt; k++){
          if ((j >> k & 1) == 1){
            id2.push_back(id[i][k]);
            sum += d[id[i][k]];
          }
        }
        int cnt2 = id2.size();
        vector<vector<int>> dp2(cnt2, vector<int>(cnt2, INF));
        for (int k = 0; k < cnt2; k++){
          for (int l = 0; l < cnt2; l++){
            dp2[k][l] = E[id2[k]][id2[l]];
          }
        }
        for (int u = 0; u < cnt2; u++){
          for (int v = 0; v < cnt2; v++){
            for (int w = 0; w < cnt2; w++){
              dp2[v][w] = min(dp2[v][w], dp2[v][u] + dp2[u][w]);
            }
          }
        }
        for (int k1 = 0; k1 < cnt2; k1++){
          for (int l1 = 0; l1 < cnt2; l1++){
            for (int k2 = 0; k2 < cnt2; k2++){
              for (int l2 = 0; l2 < cnt2; l2++){
                dp[id2[k1]][id2[l1]][id2[k2]][id2[l2]] = min(dp[id2[k1]][id2[l1]][id2[k2]][id2[l2]], dp2[k1][l1] + dp2[l2][k2] + sum);
              }
            }
          }
        }
      }
    }
    vector<int> x;
    for (int i = 0; i < h; i++){
      int cnt = id[i].size();
      for (int j = 0; j < cnt; j++){
        x.push_back(id[i][j]);
      }
    }
    vector<vector<int>> dp2(n, vector<int>(n, INF));
    dp2[0][0] = 0;
    for (int i = 0; i < n; i++){
      for (int j = 0; j < n; j++){
        int v = x[i];
        int w = x[j];
        int cnt1 = id[e[v]].size();
        int cnt2 = id[e[w]].size();
        for (int i2 = 0; i2 < cnt1; i2++){
          int v2 = id[e[v]][i2];
          for (int k = 0; k < n; k++){
            if (e[v] < e[k]){
              dp2[k][w] = min(dp2[k][w], dp2[v][w] + dp[v][v2][v][v] + E[v2][k]);
            }
          }
        }
        for (int i2 = 0; i2 < cnt2; i2++){
          int w2 = id[e[w]][i2];
          for (int k = 0; k < n; k++){
            if (e[w] < e[k]){
              dp2[v][k] = min(dp2[v][k], dp2[v][w] + dp[w][w][w][w2] + E[k][w2]);
            }
          }
        }
        if (e[v] == e[w]){
          for (int i2 = 0; i2 < cnt1; i2++){
            for (int j2 = 0; j2 < cnt2; j2++){
              int v2 = id[e[v]][i2];
              int w2 = id[e[w]][j2];
              for (int k = 0; k < n; k++){
                for (int l = 0; l < n; l++){
                  if (e[v] < e[k] && e[w] < e[l]){
                    dp2[k][l] = min(dp2[k][l], dp2[v][w] + dp[v][v2][w][w2] + E[v2][k] + E[l][w2]);
                  }
                }
              }
            }
          }
        }
      }
    }
    if (dp2[n - 1][n - 1] == INF){
      cout << -1 << endl;
    } else {
      cout << dp2[n - 1][n - 1] << endl;
    }
  }
}
accuracy: 1
time_ms: 450
memory_kb: 32032
final_rank: 11

code_snippet: #include<cstdio>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
using P = pair<int, int>;
using Q = pair<int, P>;
const int INF = 1000000000;

int n, m, d, f, a, b, c, towncost[50], dp[50][50], tmp2[50][50], tmp[50][50];
vector<P> e[50], re[50];
map<int, vector<int>> mp;
vector<int> used;
set<int> can_use;

int get(int a, int b, bool is_a_top, bool is_b_top) {
  vector<P> A, B;
  A.push_back(P(a, 0)); B.push_back(P(b, 0));
  int ans = INF;
  for (P i : (is_a_top ? re[a] : A)) if (can_use.count(i.first)) {
    for (P j : (is_b_top ? e[b] : B)) if (can_use.count(j.first)) {
      ans = min(ans, dp[i.first][j.first] + i.second + j.second);
    }
  }
  return ans;
}

int main() {
  while (scanf("%d%d", &n, &m), n) {
    mp.clear();
    used.clear();
    can_use.clear();
    for (int i = 0; i < 50; i++) {
      e[i].clear();
      re[i].clear();
      for (int j = 0; j < 50; j++) {
        dp[i][j] = INF;
      }
    }
    dp[0][0] = 0;
    for (int i = 1; i < n-1; i++) {
      scanf("%d%d", &d, &f);
      towncost[i] = d;
      mp[f].push_back(i);
    }
    towncost[0] = towncost[n-1] = 0;
    for (int i = 0; i < m; i++) {
      scanf("%d%d%d", &a, &b, &c);
      a--; b--;
      e[a].push_back(P(b, c));
      re[b].push_back(P(a, c));
    }
    mp[1000].push_back(n-1);
    used.push_back(0);
    can_use.insert(0);
    for (auto it = mp.begin(); it != mp.end(); it++) {
      vector<int> v = it->second;
      map<int, int> r;
      for (int i = 0; i < v.size(); i++) r[v[i]] = i;
      for (int i : used) for (int j : used) tmp[i][j] = dp[i][j];
      for (int i : used) for (int j : v) {
        tmp[i][j] = get(i, j, false, true);
      }
      for (int i : v) for (int j : used) {
        tmp[i][j] = get(i, j, true, false);
      }
      for (int i : v) for (int j : v) {
        tmp[i][j] = get(i, j, true, true);
      }
      for (int i : v) used.push_back(i), can_use.insert(i);
      for (int i = 1; i < (1 << v.size()); i++) {
        int sum = 0;
        for (int j = 0; j < v.size(); j++) if (i & (1 << j)) {
          sum += towncost[v[j]];
        }
        priority_queue<Q> que;
        for (int j : used) {
          for (int k : used) {
            if ((r.count(j) == 0 || (i & (1 << r[j]))) && (r.count(k) == 0 || (i & (1 << r[k])))) {
              tmp2[j][k] = tmp[j][k];
              que.push(Q(tmp2[j][k], P(j, k)));
            } else {
              tmp2[j][k] = INF;
            }
          }
        }
        while (!que.empty()) {
          Q q = que.top(); que.pop();
          int cost = q.first, j = q.second.first, k = q.second.second;
          if (tmp2[j][k] < cost) continue;
          dp[j][k] = min(dp[j][k], cost + sum);
          for (P l : e[j]) if (r.count(l.first) && (i & (1 << r[l.first]))) {
            int newcost = cost + l.second;
            if (tmp2[l.first][k] > newcost) {
              tmp2[l.first][k] = newcost;
              que.push(Q(newcost, P(l.first, k)));
            }
          }
          for (P l : re[k]) if (r.count(l.first) && (i & (1 << r[l.first]))) {
            int newcost = cost + l.second;
            if (tmp2[j][l.first] > newcost) {
              tmp2[j][l.first] = newcost;
              que.push(Q(newcost, P(j, l.first)));
            }
          }
        }
      }
    }
    if (dp[n-1][n-1] == INF) dp[n-1][n-1] = -1;
    printf("%d\n", dp[n-1][n-1]);
  }
}
accuracy: 1
time_ms: 5350
memory_kb: 2908
final_rank: 16

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <cfloat>
#include <climits>
#include <algorithm>
#include <iomanip>
#include <queue>
#include <unordered_map>
#include <string>
#include <tuple>
struct Road {
	int to, cost;
};
struct Town {
	int visit_cost, altitude;
};
struct State {
	int go_pos, return_pos, cost;
	unsigned long long int visited;
};
int main() {
	while (true) {
		int n, m; std::cin >> n >> m;
		if (n == 0 && m == 0) break;
		std::vector<Town> towns(n);
		towns[0].altitude = 0; towns.back().altitude = 1000;
		for (auto i = 1; i < n - 1; ++i) {
			std::cin >> towns[i].visit_cost >> towns[i].altitude;
		}
		std::vector<std::vector<Road>> road(n), rev_road(n);
		for (auto i = 0; i < m; ++i) {
			int a, b, c; std::cin >> a >> b >> c; --a; --b;
			if (towns[a].altitude <= towns[b].altitude) road[a].push_back(Road{ b, c });
			if (towns[b].altitude <= towns[a].altitude) rev_road[b].push_back(Road{ a, c });
		}
		std::vector<std::vector<std::unordered_map<unsigned long long int, int>>> min_cost(n, std::vector<std::unordered_map<unsigned long long int, int>>(n));
		const auto comparator = [](const State& a, const State& b) {return a.cost > b.cost; };
		std::priority_queue<State, std::vector<State>, decltype(comparator)> queue(comparator);
		min_cost[0][0][0] = 0;
		queue.push(State{ 0, 0, 0, 0 });
		while (!queue.empty()) {
			const auto top = queue.top(); queue.pop();
			if (min_cost[top.go_pos][top.return_pos][top.visited] < top.cost) continue;
			const auto max_height = std::max(towns[top.go_pos].altitude, towns[top.return_pos].altitude);
			if (towns[top.return_pos].altitude == max_height) for (const auto r : road[top.go_pos]) {
				const auto visited = towns[r.to].altitude < max_height ? top.visited : (towns[r.to].altitude == max_height ? top.visited | (1ULL << r.to) : (1ULL << r.to));
				const auto cost = r.cost + top.cost + (top.visited & (1ULL << r.to) ? 0 : towns[r.to].visit_cost);
				const auto find = min_cost[r.to][top.return_pos].find(visited);
				if (find == min_cost[r.to][top.return_pos].end() || find->second > cost) {
					min_cost[r.to][top.return_pos][visited] = cost;
					queue.push(State{ r.to, top.return_pos, cost, visited });
				}
			}
			if (towns[top.go_pos].altitude == max_height) for (const auto r : rev_road[top.return_pos]) {
				const auto visited = towns[r.to].altitude < max_height ? top.visited : (towns[r.to].altitude == max_height ? top.visited | (1ULL << r.to) : (1ULL << r.to));
				const auto cost = r.cost + top.cost + (top.visited & (1ULL << r.to) ? 0 : towns[r.to].visit_cost);
				const auto find = min_cost[top.go_pos][r.to].find(visited);
				if (find == min_cost[top.go_pos][r.to].end() || find->second > cost) {
					min_cost[top.go_pos][r.to][visited] = cost;
					queue.push(State{ top.go_pos, r.to, cost, visited });
				}
			}
		}
		const auto min = std::min_element(min_cost.back().back().begin(), min_cost.back().back().end(), [](const std::pair<unsigned long long int, int>& a, const std::pair<unsigned long long int, int>& b) {return a.second < b.second; });
		if (min == min_cost.back().back().end()) {
			std::cout << "-1\n";
		}
		else {
			std::cout << min->second << '\n';
		}
	}
}
accuracy: 1
time_ms: 260
memory_kb: 10540
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
const int inf = 1e9;

struct state{
    int s,t;
    int mask;
    int d;
    state(int s, int t, int mask, int d):s(s),t(t),mask(mask),d(d){}
    state(){}
    bool operator <(const state &a) const{
        return d > a.d;
    }
};
int solve(vector<int> &v, vector<int> &h, vector<vector<pair<int,int>>> &gs, vector<vector<pair<int,int>>> &gt){
    int n = gs.size();
    vector<int> mapping(n);
    vector<int> idx(1001, 0);
    for(int i=0; i<n; i++){
        mapping[i] = idx[h[i]]++;
    }
    vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, vector<int>(2<<10, inf)));
    dp[0][0][1<<mapping[0]] = 0;
    priority_queue<state> wait;
    wait.push(state(0, 0, 1<<mapping[0], 0));
    while(!wait.empty()){
        int s = wait.top().s;
        int t = wait.top().t;
        int mask = wait.top().mask;
        int d = wait.top().d;
        wait.pop();
        if(d > dp[s][t][mask]) continue;
        if(h[s] <= h[t]){
            for(auto next: gs[s]){
                int ns = next.first;
                int nd = d +next.second +v[ns];
                int nmask = mask;
                if(h[ns] == h[t]){
                    if(mask>>mapping[ns]&1){
                        nd -= v[ns];
                    }
                    nmask |= 1<<mapping[ns];
                }else if(h[ns] > h[t]){
                    nmask = 1<<mapping[ns];
                }
                if(nd < dp[ns][t][nmask]){
                    dp[ns][t][nmask] = nd;
                    wait.push(state(ns, t, nmask, nd));
                }
            }
        }
        if(h[t] <= h[s]){
            for(auto next: gt[t]){
                int nt = next.first;
                int nd = d +next.second +v[nt];
                int nmask = mask;
                if(h[nt] == h[s]){
                    if(mask>>mapping[nt]&1){
                        nd -= v[nt];
                    }
                    nmask |= 1<<mapping[nt];
                }else if(h[nt] > h[s]){
                    nmask = 1<<mapping[nt];
                }
                if(nd < dp[s][nt][nmask]){
                    dp[s][nt][nmask] = nd;
                    wait.push(state(s, nt, nmask, nd));
                }
            }
        }
    }
    int res = *min_element(dp[n-1][n-1].begin(), dp[n-1][n-1].end());
    if(res == inf) return -1;
    return res;
}

int main(){
    while(1){
        int n,m;
        cin >> n >> m;
        if(n == 0) break;

        vector<int> d(n), e(n);
        d[0] = d[n-1] = 0;
        e[0] = 0;
        e[n-1] = 1000;
        for(int i=1; i<n-1; i++){
            cin >> d[i] >> e[i];
        }
        vector<vector<pair<int,int>>> adj(n), rev(n);
        for(int i=0; i<m; i++){
            int a,b,c;
            cin >> a >> b >> c;
            a--; b--;
            if(e[a] <= e[b]) adj[a].emplace_back(b, c);
            if(e[a] >= e[b]) rev[b].emplace_back(a, c);
        }
        cout << solve(d, e, adj, rev) << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 26352
final_rank: 10

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>
using namespace std;
typedef long long int LL;
typedef pair<int,int> P;
typedef pair<LL,int> LP;
const int INF=1e8+7;
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<int>> path;
vector<P> va;
int t[100][2];
typedef vector<int> V1;
typedef vector<vector<int>> V2;
typedef vector<vector<vector<int>>> V3;
const int dis_n=20;
int dis[dis_n][dis_n][dis_n][dis_n];

void memset_dis(){
    int a,b,c,d;
    for(a=0;a<dis_n;a++){
        for(b=0;b<dis_n;b++){
            for(c=0;c<dis_n;c++){
                for(d=0;d<dis_n;d++){
                    dis[a][b][c][d]=INF;
                }
            }
        }
    }
}

void check(int ta,int tb,vector<int>& v1){
    if(ta<=tb){
        v1.push_back(tb-ta);
        check(ta,tb-1,v1);
        v1.pop_back();
        check(ta,tb-1,v1);
        return;
    }
    if(v1.empty())return;
    int n=v1.size();
    int i,j,k,l;
    int a,b,c,d;
    int s;
    vector<vector<int>> dis_temp(n,vector<int>(n,INF));
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            a=ta+v1[i],b=ta+v1[j];
            dis_temp[i][j]=path[a][b];
        }
    }
    for(k=0;k<n;k++){
        for(i=0;i<n;i++){
            for(j=0;j<n;j++){
                dis_temp[i][j]=min(dis_temp[i][j],dis_temp[i][k]+dis_temp[k][j]);
            }
        }
    }
    s=0;
    for(i=0;i<n;i++){
        s+=t[ta+v1[i]][0];
    }
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            for(k=0;k<n;k++){
                for(l=0;l<n;l++){
                    a=v1[i],b=v1[j],c=v1[k],d=v1[l];
                    dis[a][b][c][d]=min(dis[a][b][c][d],s+dis_temp[i][k]+dis_temp[j][l]);
                }
            }
        }
    }
}

int main(){
    int n,m;
    int i,j,k;
    int a,b,c,d;
    int x,y;
    while(cin>>n>>m){
        if(!n)break;
        path.assign(n,vector<int>(n,INF));
        va.assign(1e3+7,P(n+10,-1));
        vector<tuple<int,int,int>> vt1;
        vector<int> v1(n);
        V2 dp(n+10,V1(n+10,INF));
        vt1.push_back(make_tuple(0,0,0));
        vt1.push_back(make_tuple(1e3,0,n-1));
        for(i=1;i<n-1;i++){
            cin>>a>>b;
            vt1.push_back(make_tuple(b,a,i));
        }
        sort(vt1.begin(),vt1.end());
        for(i=0;i<n;i++){
            tie(a,b,c)=vt1[i];
            v1[c]=i;
            va[a].first=min(va[a].first,i);
            va[a].second=max(va[a].second,i);
            t[i][0]=b,t[i][1]=a;
        }
        t[n-1][1]=1e3;
        for(i=0;i<m;i++){
            cin>>a>>b>>c;
            a--,b--;
            a=v1[a],b=v1[b];
            path[a][b]=min(path[a][b],c);
        }
        for(i=0;i<n;i++){
            path[i][i]=0;
        }
        dp[0][0]=0;
        for(i=0;i<=1e3;i++){
            if(va[i].first>n)continue;
            memset_dis();
            v1.clear();
            x=va[i].first,y=va[i].second;
            check(x,y,v1);
            m=y-x+1;
            vector<vector<int>> dp_temp(m+10,vector<int>(m+10,INF));
            for(j=0;j<m;j++){
                for(k=0;k<m;k++){
                    for(a=0;a<x;a++){
                        if(path[a][x+j]==INF)continue;
                        for(b=0;b<x;b++){
                            if(path[x+k][b]==INF)continue;
                            dp_temp[j][k]=min(dp_temp[j][k],dp[a][b]+path[a][x+j]+path[x+k][b]);
                        }
                    }
                }
            }
            for(j=0;j<m;j++){
                for(k=0;k<m;k++){
                    for(a=0;a<m;a++){
                        for(b=0;b<m;b++){
                            dp[x+a][x+b]=min(dp[x+a][x+b],dp_temp[j][k]+dis[j][b][a][k]);
                        }
                    }
                }
            }
            for(j=0;j<=y;j++){
                for(a=0;a<x;a++){
                    for(b=0;b<m;b++){
                        for(c=0;c<m;c++){
                            dp[j][x+c]=min(dp[j][x+c],dp[j][a]+path[x+b][a]+dis[b][c][b][b]);
                            dp[x+c][j]=min(dp[x+c][j],dp[a][j]+path[a][x+b]+dis[b][b][c][b]);
                        }
                    }
                }
            }
        }
        int s=dp[n-1][n-1];
        if(s>=INF)s=-1;
        cout<<s<<endl;
    }
}
accuracy: 1
time_ms: 70
memory_kb: 3724
final_rank: 4

code_snippet: #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<utility>
#include<cassert>
#include<complex>
#include<numeric>
using namespace std;

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

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353/100;
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 = acos(-1.0);

ll mod_pow(ll x, ll n, ll m) {
	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 << 22;
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];
}

ll gcd(ll a, ll b) {
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}

using speP = pair<int, P>;
int cost[50][50];
int dist[50][50];

int swcost[50][50];
int n, m;
void solve() {
	vector<int> d(n), h(n);
	rep(i, n) {
		if (i == 0) {
			d[i] = 0, h[i] = 0;
		}
		else if (i == n - 1) {
			d[i] = 0, h[i] = 1000;
		}
		else {
			cin >> d[i] >> h[i];
		}
	}
	rep(i, n)rep(j, n) {
		if (i == j)cost[i][j] = 0;
		else cost[i][j] = mod;
	}
	rep(i, m) {
		int a, b, c; cin >> a >> b >> c; a--; b--;
		cost[a][b] = c;
	}
	rep(i, n) {
		rep(j, n) {
			swcost[i][j] = mod;
		}
		swcost[i][i] = d[i];
		priority_queue<P, vector<P>, greater<P>> q;
		q.push({ d[i],i });
		while (!q.empty()) {
			P p = q.top(); q.pop();
			int id = p.second;
			if (swcost[i][id] < p.first)continue;
			rep(to, n) {
				if (h[id] != h[to])continue;
				int nd = p.first + d[to] + 2 * cost[id][to];
				if (nd < swcost[i][to]) {
					swcost[i][to] = nd;
					q.push({ nd,to });
				}
			}
		}
		rep(j, n) {
			swcost[i][j] -= d[i] + d[j];
		}
	}

	rep(i, n)rep(j, n)dist[i][j] = mod;
	dist[0][0] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,{0,0} });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int x = p.second.first, y = p.second.second;
		if (dist[x][y] < p.first)continue;
		rep(nx, n) {
			if (h[x] > h[nx])continue;
			int s = p.first + cost[x][nx] + d[nx];
			if (s < dist[nx][y]) {
				dist[nx][y] = s;
				q.push({ s,{nx,y} });
			}
		}
		rep(ny, n) {
			if (h[y] > h[ny])continue;
			int s = p.first + cost[ny][y] + d[ny];
			if (s < dist[x][ny]) {
				dist[x][ny] = s;
				q.push({ s,{x,ny} });
			}
		}
		if (h[x] == h[y]&&x!=y) {
			int s = p.first + swcost[x][y];
			if (s < dist[y][x]) {
				dist[y][x] = s;
				q.push({ s,{y,x} });
			}
		}
		rep(nx, n)rep(ny, n) {
			if (h[x] > h[nx] || h[y] > h[ny])continue;
			int s = p.first + cost[x][nx] + cost[ny][y] + d[nx] + d[ny];
			if (nx == ny)s -= d[nx];
			if (s < dist[nx][ny]) {
				//cout << "? " << x << " " << y << " " << nx << " " << ny << " " << s << "\n";
				dist[nx][ny] = s;
				q.push({ s,{nx,ny} });
			}
		}
	}
	/*rep(i, n) {
		rep(j, n)cout << dist[i][j] << " ";
		cout << "\n";
	}*/
	//cout << dist[1][2]<<" "<<swcost[1][2] << "\n";
	int ans = dist[n - 1][n - 1];
	if (ans == mod)cout << -1 << "\n";
	else cout << ans << "\n";
}




signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//init_f();
	//expr();
	//int t; cin >> t; rep(i, t)
	while (cin >> n >> m, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 69076
final_rank: 17

code_snippet: #include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstring>
#include <deque>
#include <functional>
#include <iostream>
#include <iomanip>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <cstdint>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
#define MP make_pair
#define PB push_back
#define inf 1000000007
#define rep(i,n) for(int i = 0; i < (int)(n); ++i)
#define all(x) (x).begin(),(x).end()

template<typename A, size_t N, typename T>
void Fill(A (&array)[N], const T &val){
    std::fill( (T*)array, (T*)(array+N), val );
}
 
template<class T> inline bool chmax(T &a, T b){
    if(a<b){
        a = b;
        return true;
    }
    return false;
}

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

int dp[51][51][1<<10];

int main(){
    int n,m;
    while(1){
        cin >> n >> m;
        if(n==0)break;
        vector<int>h(n);
        map<int,int> ss;
        vector<int> num(n);
        vector<int> c(n);
        rep(i,n-2){
            cin >> c[i+1] >> h[i+1];
            num[i+1] = ss[h[i+1]];
            ss[h[i+1]]++;
        }
        rep(i,n)rep(j,n)rep(k,1<<10)dp[i][j][k] = inf;
        h[0] = 0;
        h[n-1] = 1000;
        vector<vector<pii> > gu(n);
        vector<vector<pii> > gd(n);
        vector<vector<pii> > u(n);
        vector<vector<pii> > d(n);
        rep(i,m){
            int a,b,e;
            cin >> a >> b >> e;
            a--;b--;
            if(h[a]==h[b]){
                gu[a].push_back(MP(b,e));
                gd[b].push_back(MP(a,e));
                u[a].push_back(MP(b,e));
                d[b].push_back(MP(a,e));
            }else if(h[a]<h[b]){
                u[a].push_back(MP(b,e));
            }else{
                d[b].push_back(MP(a,e));
            }
        }
        priority_queue<pair<pii,pair<int,int>>,vector<pair<pair<int,int>,pii>>,greater<pair<pair<int,int>,pii>> >pq;
        dp[0][0][1] = 0;
        pq.push(MP(MP(0,1),MP(0,0)));
        while(!pq.empty()){
            auto x = pq.top();
            pq.pop();
            int a = x.second.first;
            int b = x.second.second;
            int cost = x.first.first;
            int reach = x.first.second;
            if(dp[a][b][reach]!=cost)continue;
            // cerr << a << " " << b << " " << cost << " " << reach << endl;
            if(h[a]<=h[b]){
                for(auto x:u[a]){
                    int nxt = x.first;
                    int dd = cost + x.second;
                    int nxtreach = reach;
                    if(h[nxt]<h[b]){
                        dd += c[nxt];
                        if(chmin(dp[nxt][b][nxtreach],dd)){
                            pq.push(MP(MP(dp[nxt][b][nxtreach],nxtreach),MP(nxt,b)));
                        }
                    }else if(h[nxt]>h[b]){
                        dd += c[nxt];
                        nxtreach = (1<<num[nxt]);
                        if(chmin(dp[nxt][b][nxtreach],dd)){
                            pq.push(MP(MP(dp[nxt][b][nxtreach],nxtreach),MP(nxt,b)));
                        }
                    }else{
                        if(nxt!=b){
                            dd += c[nxt];
                            nxtreach = reach|(1<<num[nxt]);
                        }
                        if(chmin(dp[nxt][b][nxtreach],dd)){
                            pq.push(MP(MP(dp[nxt][b][nxtreach],nxtreach),MP(nxt,b)));
                        }
                    }
                }
            }
            if(h[b]<=h[a]){
                for(auto x:d[b]){
                    int nxt = x.first;
                    int dd = cost + x.second;
                    int nxtreach = reach;
                    if(h[nxt]<h[a]){
                        dd += c[nxt];
                        if(chmin(dp[a][nxt][nxtreach],dd)){
                            pq.push(MP(MP(dp[a][nxt][nxtreach],nxtreach),MP(a,nxt)));
                        }
                    }else if(h[nxt]>h[a]){
                        dd += c[nxt];
                        nxtreach = (1<<num[nxt]);
                        if(chmin(dp[a][nxt][nxtreach],dd)){
                            pq.push(MP(MP(dp[a][nxt][nxtreach],nxtreach),MP(a,nxt)));
                        }
                    }else{
                        if(nxt!=a){
                            dd += c[nxt];
                            nxtreach = reach|(1<<num[nxt]);
                        }
                        if(chmin(dp[a][nxt][nxtreach],dd)){
                            pq.push(MP(MP(dp[a][nxt][nxtreach],nxtreach),MP(a,nxt)));
                        }
                    }
                }
            }
            if(h[a]==h[b]){
                for(auto x:gu[a]){
                    int nxt = x.first;
                    int dd = cost + x.second;
                    int nxtreach = reach;
                    
                    if(((reach>>num[nxt])&1)==0){
                        dd += c[nxt];
                        nxtreach = reach|(1<<num[nxt]);
                    }
                    if(chmin(dp[nxt][b][nxtreach],dd)){
                        pq.push(MP(MP(dp[nxt][b][nxtreach],nxtreach),MP(nxt,b)));
                    }
                    
                }
                for(auto x:gd[b]){
                    int nxt = x.first;
                    int dd = cost + x.second;
                    int nxtreach = reach;
                    
                    if(((reach>>num[nxt])&1)==0){
                        dd += c[nxt];
                        nxtreach = reach|(1<<num[nxt]);
                    }
                    if(chmin(dp[a][nxt][nxtreach],dd)){
                        pq.push(MP(MP(dp[a][nxt][nxtreach],nxtreach),MP(a,nxt)));
                    }
                    
                }
            }
        }
        if(dp[n-1][n-1][1]==inf){
            cout << -1 << endl;
        }else{
            cout << dp[n-1][n-1][1] << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 15108
final_rank: 9