#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