#pragma GCC optimize ("O3")
#include <bits/stdc++.h>

using namespace std;

#define llong long long 
#define len(x) ((int)x.size())
#define rep(i,n) for (int i = -1; ++ i < n; )
#define rep1(i,n) for (int i = 0; i ++ < n; )
#define rand __rand
mt19937 rng(chrono::system_clock::now().time_since_epoch().count());  // or mt19937_64
template<class T = int> T rand(T range = numeric_limits<T>::max()) { return (T)(rng() % range); }

#define CONCAT_(x, y) x##y/*{{{*/
#define CONCAT(x, y) CONCAT_(x, y)
#define SPEC(name) CONCAT(name, __LINE__)
#ifdef LOCAL_DEBUG   
int __db_level = 0;
#define clog cerr << string(__db_level * 2, ' ')
struct debug_block {
    string msg;
    debug_block(const string& s): msg(s) { clog << "{ " << msg << endl; ++__db_level; }
    ~debug_block() { --__db_level; clog << "} " << msg << endl; }
};
#define DB(args...) stringstream SPEC(ss); SPEC(ss)<< args; debug_block SPEC(dbbl)(SPEC(ss).str())
#else
#define clog if (0) cerr
#define DB(...)
#endif
#define db(val) "[" #val " = " << val << "]; "
template<class U, class V> ostream& operator<<(ostream& out, const pair<U, V>& p) {
    return out << "(" << p.first << ", " << p.second << ")";
}
template<size_t i, class T> ostream& print_tuple_utils(ostream& out, const T& tup) {
    if (i == tuple_size<T>::value) return out << ")";
    else return print_tuple_utils<i + 1, T>(out << (i ? ", " : "(") << get<i>(tup), tup);
}
template<class ...U>
ostream& operator<<(ostream& out, const tuple<U...>& tup) { return print_tuple_utils<0, tuple<U...>>(out, tup); }
template<class, typename = void> struct has_const_iterator : false_type {};
template<class T> struct has_const_iterator<T, void_t<typename T::const_iterator>> : true_type {};
template<class T>
typename enable_if<has_const_iterator<T>::value && !is_same<T, string>::value, ostream&>::type
operator<<(ostream& out, const T& container) { 
    auto beg = container.begin(), end = container.end();
    out << "(" << container.size() << ") {";
    if (beg != end) out << *(beg++);
    while (beg != end) out << ", " << *(beg++);
    return out << "}";
}
/*}}}*/
// ACTUAL SOLUTION BELOW ////////////////////////////////////////////////////////////

const int maxn = 500010;
const int maxm = 1000000 + 10;
struct Query {
    int type, l, r, h;
    int ans;
    Query() {}
    void upd_ans(int oh) {
        ans = min(ans, abs(h - oh));
    }
};

int n, m;
Query qr[maxm];
vector<int> sorted_values[maxn * 2], sorted_times[maxn * 2];

void add_point(vector<int>* cont, int p, int id) {
    for (cont[p += n].push_back(id); p > 1; p >>= 1) cont[p >> 1].push_back(id);
}

void add_range(vector<int>* cont, int l, int r, int id) {
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
        if (l & 1) cont[l++].push_back(id);
        if (r & 1) cont[--r].push_back(id);
    }
}

int cnt[maxm], dsu[maxm];
int find_set(int u) {
    return dsu[u] < 0 ? u : dsu[u] = find_set(dsu[u]);
}

int join(int u, int v) {
    u = find_set(u);
    v = find_set(v);
    if (u == v) return u;
    if (-dsu[u] < -dsu[v]) swap(u, v);
    dsu[u] += dsu[v];
    dsu[v] = u;
    cnt[u] += cnt[v];
    return u;
}

void cal_ans_then_clear(int node) {
    DB(db(node));
    static int left[maxm], right[maxm];
    auto& sv = sorted_values[node], &st = sorted_times[node];
    clog << db(sv) << endl; 
    clog << db(st) << endl; 
    assert(len(sv) == len(st));
    int prv = -1;
    for (auto i: sv) {
        dsu[i] = -1;
        cnt[i] = 1;
        left[i] = prv;
        if (prv != -1) right[prv] = i;
        prv = i;
    }
    if (prv != -1) right[prv] = -1;
    
    reverse(st.begin(), st.end());
    for (auto i: st) {
        clog << db(i) << endl; 
        int cur = find_set(i);
        if (qr[i].type == 1) {
            while (left[cur] != -1 and qr[left[cur]].type == 1) {
                clog << "left " << db(cur) << db(left[cur]) << db(right[cur]) << endl;  
                assert(find_set(cur) != find_set(left[cur]));
                int ol = left[cur], oc = cur;
                cur = join(cur, ol);
                left[cur] = left[ol];
                right[cur] = right[oc];
                if (left[cur] != -1) right[left[cur]] = cur;
                if (right[cur] != -1) left[right[cur]] = cur;
            }
            while (right[cur] != -1 and qr[right[cur]].type == 1) {
                clog << "right " << db(cur) << db(left[cur]) << db(right[cur]) << endl;  
                assert(find_set(cur) != find_set(right[cur]));
                int oldr = right[cur], oc = cur;
                cur = join(cur, oldr);
                left[cur] = left[oc];
                right[cur] = right[oldr];
                if (left[cur] != -1) right[left[cur]] = cur;
                if (right[cur] != -1) left[right[cur]] = cur;
            }
            
            if (left[cur] != -1) {
                qr[i].upd_ans(qr[left[cur]].h);
            }
            if (right[cur] != -1) {
                qr[i].upd_ans(qr[right[cur]].h);
            }
        }
        --cnt[cur];
        if (cnt[cur]) continue;
        if (left[cur] != -1) right[left[cur]] = right[cur];
        if (right[cur] != -1) left[right[cur]] = left[cur];
    }
    
    sv.clear();
    st.clear();
    clog << db(sv) << endl;
    clog << db(st) << endl;
}
 
// #define testing    
int main(void) {
    rng.seed(177013);
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    
#ifndef testing
    int ntest; cin >> ntest;
#else
    int ntest = 10000;
#endif
    while (ntest--) {
#ifndef testing
        cin >> n >> m;
#else
        n = 10; m = 10;
        vector<int> pos_for_0(n);
        rep(i, n) pos_for_0[i] = i + 1;
        shuffle(pos_for_0.begin(), pos_for_0.end(), rng);
#endif
        n += 10;
        rep(i, m) {
            int qr_type, qr_l, qr_r = -1, qr_h;
#ifndef testing
            cin >> qr_type;
            if (qr_type) cin >> qr_l >> qr_r >> qr_h;
            else cin >> qr_l >> qr_h;
#else
            qr_type = (len(pos_for_0) ? rand(2) : 1);
            if (qr_type == 0) {
                qr_l = pos_for_0.back();
                pos_for_0.pop_back();
            } else {
                qr_l = rand(n) + 1;
                qr_r = rand(n) + 1;
                if (qr_l > qr_r) swap(qr_l, qr_r);
            }
            qr_h = rand(1000000000) + 1;
#endif
            
            qr[i].type = qr_type;
            qr[i].l = qr_l - 1;
            qr[i].r = qr_r;
            qr[i].h = qr_h;
            qr[i].ans = INT_MAX;
        }
        
        clog << "Add by times" << endl;
        rep(i, m) {
            // clog << db(i) << endl; 
            if (qr[i].type == 0) add_point(sorted_times, qr[i].l, i);
            else add_range(sorted_times, qr[i].l, qr[i].r, i);
        }
        
        clog << "Sorting" << endl;
        vector<int> pos(m);
        rep(i, m) pos[i] = i;
        sort(pos.begin(), pos.end(), [&](int u, int v) { return qr[u].h < qr[v].h; });
        clog << "Add by values" << endl;
        for (auto i: pos) {
            // clog << db(i) << endl; 
            if (qr[i].type == 0) add_point(sorted_values, qr[i].l, i);
            else add_range(sorted_values, qr[i].l, qr[i].r, i);
        }
        pos.clear();
        
        
        rep(i, 2 * n) cal_ans_then_clear(i);
#ifndef testing
        rep(i, m) {
            if (qr[i].type == 0) continue;
            if (qr[i].ans >= INT_MAX) cout << "-1\n";
            else cout << qr[i].ans << '\n';
        }
#else
        cout << "OK" << endl;
#endif
    }
    

    return 0;
}

// Remember:
// - Multitest? REFRESHING the data!!!
// - Constrains for each set of data may differs. Should NOT USE the same max constant (maxn)
//   for all of them.
// vim: foldmethod=marker
 