#include <queue>
#include <cstdio>
#include <cctype>
#include <climits>
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define Smerenie 500001
#define Nadejde 250001
#define Dragoste 65536
#define MAX_K 1001
typedef struct {
int v, k, next;
} cell;
typedef struct {
int v, k;
} cerr;
int N;
int M;
int X;
int Y;
char c;
int d[Nadejde];
int adj[Nadejde];
cell l[Smerenie];
cerr list[Nadejde];
int pos = Dragoste;
char seen[Nadejde];
char buff[Dragoste];
std::queue <int> Q[MAX_K + 1];
/** Returneaza urmatorul caracter din "f". **/
char getChar(FILE *f) {
if (pos == Dragoste) {
fread(buff, 1, Dragoste, f);
pos = 0;
}
return buff[pos++];
}
/** Citeste urmatorul numar. **/
void read(FILE *f, int *result) {
*result = 0;
do {
c = getChar(f);
} while (!isdigit(c));
do {
*result = (*result << 3) + (*result << 1) + c - '0';
c = getChar(f);
} while (isdigit(c));
}
/** Inlocuim fscanf()-ul. **/
void freef(FILE *f, const char *arg, int *u, int *v, int *k) {
read(f, &*u), read(f, &*v), read(f, &*k);
}
/** Adauga-l pe "v" la lista de adiacenta a lui "u". **/
void addEdge(int u, int v, int k, int p) {
l[p].v = v;
l[p].k = k;
l[p].next = adj[u];
adj[u] = p;
}
/** Sorteaza crescator vectorul "list". **/
void qSort(int begin, int end) {
int e = end, b = begin, pivot = list[(e + b) >> 1].v;
while (b <= e) {
while (list[b].v < pivot) {
b++;
}
while (list[e].v > pivot) {
e--;
}
if (b <= e) {
cerr tmp = list[b];
list[b++] = list[e];
list[e--] = tmp;
}
}
if (begin < e) {
qSort(begin, e);
}
if (b < end) {
qSort(b, end);
}
}
/** Sorteaza lista de adiacenta a nodului "u". **/
void getAdj(int u) {
int size = 0;
for (pos = adj[u]; pos; pos = l[pos].next) {
list[size].v = l[pos].v;
list[size++].k = l[pos].k;
}
if (size > 0) {
qSort(0, size - 1);
size = 0;
for (pos = adj[u]; pos; pos = l[pos].next) {
l[pos].v = list[size].v;
l[pos].k = list[size++].k;
}
}
}
/** Determina "k" minim pana la Y. **/
int bellFord(int u, int max) {
int i, v, curr;
d[u] = 0;
Q[0].push(u);
for (i = 0; i <= max; i++) {
while (!Q[i].empty()) {
u = Q[i].front();
Q[i].pop();
if (!seen[u]) {
seen[u] = 1;
/** Pentru fiecare vecin. **/
for (pos = adj[u]; pos; pos = l[pos].next) {
v = l[pos].v;
curr = MAX(l[pos].k, d[u]);
/** Daca am gasit un "k" mai bun. **/
if (curr < d[v]) {
d[v] = curr;
Q[curr].push(v);
}
}
}
}
}
return d[Y];
}
int main(void) {
int i, u, v, k, max = 1;
FILE *f = fopen("pscnv.in", "r");
freef(f, "%d %d %d", &N, &M, &X), read(f, &Y);
for (i = 1; i <= M; i++) {
freef(f, "%d %d %d", &u, &v, &k);
addEdge(u, v, k, i);
if (k > max) {
max = k;
}
}
fclose(f);
f = fopen("pscnv.out", "w");
/** Sorteaza listele de adiacenta. **/
for (u = 1; u <= N; u++) {
getAdj(u);
d[u] = INT_MAX;
}
fprintf(f, "%d\n", bellFord(X, max));
fclose(f);
/** Multumim Doamne! **/
puts("Doamne ajuta!");
return 0;
}