#include <bits/stdc++.h>
using namespace std;
template <typename T>
struct op {
T s, m;
op() : s(0), m(numeric_limits<T>::min() >> 2) {}
op(T s, T m) : s(s), m(m) {}
op operator+(const op &other) {
return op{s + other.s, max(m + other.s, other.m)};
}
};
template <typename T, typename F>
class lazy_segment_tree {
private:
int n;
vector<T> seg;
vector<F> lazy;
static constexpr bool is_op = std::same_as<F, op<T>>;
public:
lazy_segment_tree(int n) : n(n), seg(4 * n), lazy(8 * n, F{}) {}
void push(int v, int tl, int tr) {
if constexpr (is_op) {
seg[v] = max(seg[v] + lazy[v].s, lazy[v].m);
} else {
seg[v] = seg[v] + lazy[v];
}
lazy[2 * v] = lazy[2 * v] + lazy[v];
lazy[2 * v + 1] = lazy[2 * v + 1] + lazy[v];
if constexpr (is_op) {
lazy[v] = F{};
} else {
lazy[v] = 0;
}
}
void update(int v, int tl, int tr, int l, int r, F oper) {
push(v, tl, tr);
if (tr < l || r < tl) {
return;
}
if (l <= tl && tr <= r) {
lazy[v] = lazy[v] + oper;
push(v, tl, tr);
return;
}
int tm = (tl + tr) / 2;
update(2 * v, tl, tm, l, r, oper);
update(2 * v + 1, tm + 1, tr, l, r, oper);
seg[v] = max(seg[2 * v], seg[2 * v + 1]);
}
void update(int l, int r, F oper) { update(1, 0, n - 1, l, r, oper); }
void chmax(int l, int r)
requires std::same_as<F, op<T>>
{ update(1, 0, n - 1, l, r, {0, 0}); }
void add(int l, int r, T del)
requires std::same_as<F, op<T>>
{ update(1, 0, n - 1, l, r, {del, numeric_limits<T>::min() >> 2}); }
T query(int v, int tl, int tr, int idx) {
push(v, tl, tr);
if (tr < idx || idx < tl) {
return numeric_limits<T>::min() >> 2;
}
if (idx <= tl && tr <= idx) {
return seg[v];
}
int tm = (tl + tr) / 2;
return max(query(2 * v, tl, tm, idx), query(2 * v + 1, tm + 1, tr, idx));
}
T query(int idx) { return query(1, 0, n - 1, idx); }
template <typename Fn>
int min_right(int v, int tl, int tr, const Fn &f) {
push(v, tl, tr);
if (!f(seg[v])) {
return -1;
}
if (tl == tr) {
return tl;
}
int tm = (tl + tr) / 2;
int l = min_right(2 * v, tl, tm, f);
if (l != -1) {
return l;
}
return min_right(2 * v + 1, tm + 1, tr, f);
}
template <typename Fn>
int min_right(const Fn &f) { return min_right(1, 0, n - 1, f); }
};
struct query {
int t, l, r, a;
int64_t c, k, b;
};
struct question {
int i;
int64_t b;
int idx;
bool operator<(const question &r) { return b < r.b; }
};
const int64_t inf = numeric_limits<int64_t>::max() >> 2;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m, q;
cin >> n >> m >> q;
vector<query> queries(q);
for (int i = 0; i < q; ++i) {
auto &[t, l, r, a, c, k, b] = queries[i];
cin >> t;
if (t == 1) {
cin >> l >> r >> c >> k;
--l, --r;
} else if (t == 2) {
cin >> l >> r >> k;
--l, --r;
} else {
cin >> a >> b;
--a;
}
}
lazy_segment_tree<int64_t, int64_t> st_tot(n);
lazy_segment_tree<int64_t, op<int64_t>> st_cur(n);
vector<vector<question>> questions(n);
int cnt = 0;
for (int i = 0; i < q; ++i) {
auto &[t, l, r, a, c, k, b] = queries[i];
if (t == 1) {
st_tot.update(l, r, k);
st_cur.add(l, r, k);
} else if (t == 2) {
st_cur.add(l, r, -k);
st_cur.chmax(l, r);
} else {
questions[a].push_back({cnt++, b + st_tot.query(a) - st_cur.query(a), i});
}
}
for (auto &i : questions) {
sort(i.rbegin(), i.rend());
}
lazy_segment_tree<int64_t, int64_t> st(n);
for (int i = 0; i < n; ++i) {
st.update(i, i, -(questions[i].empty() ? inf : questions[i].back().b));
}
vector<int> ans(cnt);
for (int i = 0; i < q; ++i) {
auto &[t, l, r, a, c, k, b] = queries[i];
if (t == 1) {
st.update(l, r, k);
auto f = [&](int64_t x) { return x >= 0; };
for (int idx = st.min_right(f); idx != -1; idx = st.min_right(f)) {
int sz = questions[idx].size();
if (questions[idx][sz - 1].idx > i) {
ans[questions[idx][sz - 1].i] = c;
}
if (sz >= 2) {
int64_t del = questions[idx][sz - 2].b - questions[idx][sz - 1].b;
questions[idx].pop_back();
st.update(idx, idx, -del);
} else {
st.update(idx, idx, -inf);
}
}
}
}
for (int &i : ans) {
cout << i << '\n';
}
}