#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
 
using namespace std;
 
// Số lượng nút tối đa: N ban đầu + M nút mới (nội bộ) <= 400005
const int MAX_NODES = 400005;
const int LOG_MAX = 20; 
 
// ------------------- DSU (Union-Find) -------------------
int parent_dsu[MAX_NODES]; 
int find_set(int v) {
    if (v == parent_dsu[v])
        return v;
    return parent_dsu[v] = find_set(parent_dsu[v]);
}
 
// ------------------- Cây Kruskal và Binary Lifting -------------------
int current_node;           
int up[MAX_NODES][LOG_MAX];     
long long node_cost[MAX_NODES]; 
int depth[MAX_NODES];           
 
void init(int n) {
    for (int i = 1; i <= n; ++i) {
        parent_dsu[i] = i; 
        depth[i] = 0;      
        up[i][0] = 0;      
        node_cost[i] = 0; 
    }
    // Khởi tạo các nút có thể được tạo ra
    for (int i = n + 1; i < MAX_NODES; ++i) {
        up[i][0] = 0;
        depth[i] = 0;
    }
    current_node = n;
}
 
void union_sets(int u, int v, long long w) {
    int root_u = find_set(u);
    int root_v = find_set(v);
 
    if (root_u != root_v) {
        current_node++;
        int new_root = current_node;
 
        // 1. DSU: Hợp nhất
        parent_dsu[root_u] = new_root;
        parent_dsu[root_v] = new_root;
        parent_dsu[new_root] = new_root;
 
        // 2. Cây Kruskal: Trọng số và Độ sâu
        node_cost[new_root] = w; 
        depth[new_root] = max(depth[root_u], depth[root_v]) + 1;
 
        // 3. Binary Lifting: Cập nhật nút cha
        up[root_u][0] = new_root;
        up[root_v][0] = new_root;
 
        // Tiền xử lý các bước nhảy lớn hơn cho nút mới
        for (int k = 1; k < LOG_MAX; ++k) {
            up[new_root][k] = up[up[new_root][k - 1]][k - 1];
        }
    }
}
 
// Hàm tìm LCA
int find_lca(int u, int v) {
    // 1. Đảm bảo u là nút sâu hơn
    if (depth[u] < depth[v]) swap(u, v);
 
    // 2. Đưa u lên cùng độ sâu với v
    for (int k = LOG_MAX - 1; k >= 0; --k) {
        if (up[u][k] != 0 && depth[u] - (1 << k) >= depth[v]) {
            u = up[u][k];
        }
    }
 
    if (u == v) return u; 
 
    // 3. Nhảy lên từ u và v đồng thời
    for (int k = LOG_MAX - 1; k >= 0; --k) {
        // Chỉ nhảy nếu nút cha khác nhau VÀ không phải nút 0 (null)
        if (up[u][k] != up[v][k] && up[u][k] != 0) {
            u = up[u][k];
            v = up[v][k];
        }
    }
 
    // 4. LCA là nút cha (tổ tiên 2^0) của u (hoặc v) hiện tại
    return up[u][0];
}
 
long long query_min_max_cost(int s, int t) {
    // 1. Kiểm tra tính liên thông: Nếu gốc DSU khác nhau, chưa thể đi
    if (find_set(s) != find_set(t)) {
        return -1;
    }
 
    // 2. Kiểm tra trường hợp đặc biệt: Nếu s và t đã được kết nối 
    // nhưng chưa có nút nội bộ nào được tạo ra (tức là chỉ có các nút lá)
    // Trường hợp này không nên xảy ra nếu find_set(s) == find_set(t)
    // và thuật toán đã chạy đúng.
 
    // 3. Tìm LCA
    int lca = find_lca(s, t);
 
    // 4. Kết quả là giá trị tại nút LCA
    // Nếu LCA là 0 (điều kiện này chỉ xảy ra nếu s và t không liên thông hoặc 
    // lca là nút lá, nhưng lca phải là nút nội bộ nếu s != t và đã liên thông)
    if (lca == 0) return -1; // Fallback an toàn, mặc dù về mặt lý thuyết lca > n.
 
    return node_cost[lca];
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
 
    int n, m;
    if (!(cin >> n >> m)) return 0;
 
    init(n);
 
    for (int i = 0; i < m; ++i) {
        int u, v, s, t;
        long long w;
        if (!(cin >> u >> v >> w >> s >> t)) break;
 
        // 1. Thêm cạnh 
        union_sets(u, v, w);
 
        // 2. Truy vấn
        cout << query_min_max_cost(s, t) << "\n";
    }
 
    return 0;
}