//
// Created by GRH on 2020/10/7.
//
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <unordered_map>
using namespace std;
int N = 0;
/*
*
* 内层线段树,维护位置出现的次数
*/
#define INNER_NODE_NUM (50005 * 350)
int L[INNER_NODE_NUM];
int R[INNER_NODE_NUM];
int lc[INNER_NODE_NUM];
int rc[INNER_NODE_NUM];
int _val[INNER_NODE_NUM];
int _add_flag[INNER_NODE_NUM];
int g_idx = 1;
// 初始化
void init(int idx, int start, int end, int val) {
L[idx] = start;
R[idx] = end;
lc[idx] = rc[idx] = 0;
_val[idx] = val;
_add_flag[idx] = 0;
}
// 初始化内层线段树
int init_inner(int n) {
int root = g_idx++;
L[root] = 0, R[root] = n-1;
_val[root] = 0;
_add_flag[root] = 0;
lc[root] = 0;
rc[root] = 0;
return root;
}
// 向上更新函数
void push_up(int idx) {
// 此处以求和为例,区间数值和等于子区间数值和相加
int l = lc[idx], r = rc[idx];
_val[idx] = _val[l] + _val[r];
}
// 懒标记下移函数, 区间节点上所有字段记录的均是懒标记作用之后的最新数值
void push_down(int idx) {
if (L[idx] == R[idx]) {
return;
}
// 动态开点
int mid = (L[idx] + R[idx]) >> 1;
if (!lc[idx]) {
lc[idx] = g_idx++;
init(lc[idx], L[idx], mid, 0);
}
if (!rc[idx]) {
rc[idx] = g_idx++;
init(rc[idx], mid+1, R[idx], 0);
}
int l = lc[idx], r = rc[idx];
_add_flag[l] += _add_flag[idx];
_val[l] += _add_flag[idx] * (R[l]-L[l]+1);
_add_flag[r] += _add_flag[idx];
_val[r] += _add_flag[idx] * (R[r]-L[r]+1);
_add_flag[idx] = 0;
}
// 区间加上一个数
void _add_range(int idx, int start, int end, long long val) {
if (start == L[idx] && end == R[idx]) {
_val[idx] += val * (R[idx]-L[idx]+1);
_add_flag[idx] += val;
return;
}
push_down(idx);
int mid = (L[idx] + R[idx]) >> 1;
if (end <= mid) {
_add_range(lc[idx], start, end, val);
} else if (start >= mid + 1) {
_add_range(rc[idx], start, end, val);
} else {
_add_range(lc[idx], start, mid, val);
_add_range(rc[idx], mid+1, end, val);
}
push_up(idx);
}
// 获取区间和
long long _get_range_sum(int idx, int start, int end) {
if (start == L[idx] && end == R[idx]) {
return _val[idx];
}
push_down(idx);
int mid = (L[idx] + R[idx]) >> 1;
int ans = 0;
if (end <= mid) {
ans += _get_range_sum(lc[idx], start, end);
} else if (start >= mid+1) {
ans += _get_range_sum(rc[idx], start, end);
} else {
ans += _get_range_sum(lc[idx], start, mid);
ans += _get_range_sum(rc[idx], mid+1, end);
}
push_up(idx);
return ans;
}
/*
*
* 外层线段树,维护数值区间
*/
#define OUTTER_NODE_NUM (50005 * 20)
int LL[OUTTER_NODE_NUM];
int RR[OUTTER_NODE_NUM];
int inner_root[50005 * 20]; // 内层线段树的根的id
// 递归构建线段树
void build(int idx, int l, int r)
{
LL[idx] = l, RR[idx] = r;
inner_root[idx] = init_inner(N+1);
if (l == r) {
return;
}
int mid = (l + r) >> 1;
build(idx << 1, l, mid);
build((idx << 1) | 1, mid + 1, r);
}
// 更新数值, 在数值是pos位置添加a-b的位置每个位置一次
void _update_single(int idx, int pos, int a, int b) {
_add_range(inner_root[idx], a, b, 1);
if (LL[idx] == RR[idx]) {
return;
}
int mid = (LL[idx] + RR[idx]) >> 1;
if (pos <= mid) {
_update_single(idx << 1, pos, a, b);
} else {
_update_single((idx << 1) | 1, pos, a, b);
}
}
// 从a位置到b位置第c大的数值
int _get_range_max(int idx, int a, int b, int c) {
if (LL[idx] == RR[idx]) {
return LL[idx];
}
int cnt2 = _get_range_sum(inner_root[(idx<<1) | 1], a, b);
if (cnt2 >= c) {
return _get_range_max((idx<<1 | 1), a, b, c);
} else {
return _get_range_max((idx<<1), a, b, c-cnt2);
}
}
int op[50005];
int aa[50005];
int bb[50005];
int cc[50005];
int m_idx = 0;
vector<int> mm;
vector<int> uni;
unordered_map<int, int> val2idx; // 离散化数据表
int main(void) {
//freopen("/Users/grh/Programming/CLionProjects/Test/data.txt", "r", stdin);
int n, m;
scanf("%d %d", &n, &m);
N = n;
int cmd, a, b, c;
for (int i = 0; i < m; i++) {
scanf("%d %d %d %d", &cmd, &a, &b, &c);
op[i] = cmd, aa[i] = a, bb[i] = b, cc[i] = c;
if (cmd == 1) {
mm.push_back(c);
}
}
sort(mm.begin(), mm.end());
int last_val = 0x7fffffff;
for (auto val : mm) {
if (val != last_val) {
uni.push_back(val);
val2idx[val] = uni.size()-1;
}
last_val = val;
}
build(1, 0, uni.size()-1);
for (int i = 0; i < m; i++) {
cmd = op[i], a = aa[i], b = bb[i], c = cc[i];
if (cmd == 1) {
_update_single(1, val2idx[c], a, b);
} else {
int ans = _get_range_max(1, a, b, c);
printf("%d\n", uni[ans]);
}
}
return 0;
}