#include using namespace std; using ll = long long; const ll INF = (ll)4e18; struct Node { ll sum; // 区間の和 ll minv; // 区間の最小値 ll second_min; // 区間内で 2 番目に小さい値 int cnt_min; // 区間内で最小値と等しい要素の個数 }; int N, K, Q; vector A; vector> updates; vector ql, qr; vector qx; vector L, R; // 並列二分探索用左右端 vector seg; // ノード v を子にプッシュダウン void pushdown(int v) { for(int c : {v<<1, v<<1|1}) { if (seg[c].minv < seg[v].minv) { // 葉でないなら,子の最小値を seg[v].minv に引き上げ ll delta = seg[v].minv - seg[c].minv; seg[c].sum += delta * seg[c].cnt_min; seg[c].minv = seg[v].minv; } } } // 子から情報を引き上げ void pull(int v) { const Node &L = seg[v<<1], &R = seg[v<<1|1]; Node &U = seg[v]; U.sum = L.sum + R.sum; if (L.minv < R.minv) { U.minv = L.minv; U.cnt_min = L.cnt_min; U.second_min = min(L.second_min, R.minv); } else if (L.minv > R.minv) { U.minv = R.minv; U.cnt_min = R.cnt_min; U.second_min = min(L.minv, R.second_min); } else { U.minv = L.minv; U.cnt_min = L.cnt_min + R.cnt_min; U.second_min = min(L.second_min, R.second_min); } } // 区間 [l..r] を走査し,A[i] = max(A[i], x) を行う void range_chmax(int v, int l, int r, int ql, int qr, ll x) { if (r < ql || qr < l || seg[v].minv >= x) return; if (ql <= l && r <= qr && seg[v].second_min > x) { // この区間中、最小値以外はすでに x 以上 ll delta = x - seg[v].minv; seg[v].sum += delta * seg[v].cnt_min; seg[v].minv = x; return; } pushdown(v); int m = (l + r) >> 1; range_chmax(v<<1, l, m, ql, qr, x); range_chmax(v<<1|1, m+1, r, ql, qr, x); pull(v); } // 区間和を返す ll query_sum(int v, int l, int r, int ql, int qr) { if (r < ql || qr < l) return 0; if (ql <= l && r <= qr) return seg[v].sum; pushdown(v); int m = (l + r) >> 1; return query_sum(v<<1, l, m, ql, qr) + query_sum(v<<1|1, m+1, r, ql, qr); } // 初期木を構築 void build(int v, int l, int r) { if (l == r) { seg[v].sum = A[l]; seg[v].minv = A[l]; seg[v].second_min = INF; seg[v].cnt_min = 1; return; } int m = (l + r) >> 1; build(v<<1, l, m); build(v<<1|1, m+1, r); pull(v); } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> N >> K >> Q; A.resize(N); for(int i = 0; i < N; i++) cin >> A[i]; updates.resize(K); for(int i = 0; i < K; i++){ int l, r; ll x; cin >> l >> r >> x; --l; --r; updates[i] = make_tuple(l, r, x); } ql.resize(Q); qr.resize(Q); qx.resize(Q); for(int i = 0; i < Q; i++){ cin >> ql[i] >> qr[i] >> qx[i]; --ql[i]; --qr[i]; } // 並列二分探索の左右端を初期化 L.assign(Q, 0); R.assign(Q, K+1); // 初期の A で条件を満たすクエリは r=0 にする vector pref(N+1, 0); for(int i = 0; i < N; i++) pref[i+1] = pref[i] + A[i]; for(int i = 0; i < Q; i++){ ll s = pref[qr[i]+1] - pref[ql[i]]; if (s >= qx[i]) { R[i] = 0; } } seg.assign(4*N+4, Node()); // 並列二分探索 main loop vector> bucket(K+2); while (true) { bool any = false; for(int i = 1; i <= K; i++) bucket[i].clear(); for(int i = 0; i < Q; i++){ if (L[i] + 1 < R[i]){ int mid = (L[i] + R[i]) >> 1; bucket[mid].push_back(i); any = true; } } if (!any) break; // 木を構築 build(1, 0, N-1); // updates を 1..K 順に適用しながら、bucket を処理 for(int i = 1; i <= K; i++){ auto [l, r, x] = updates[i-1]; range_chmax(1, 0, N-1, l, r, x); for(int qi : bucket[i]){ ll s = query_sum(1, 0, N-1, ql[qi], qr[qi]); if (s >= qx[qi]) R[qi] = i; else L[qi] = i; } } } // 結果出力 // R[i] == 0 → 0 回目 (初めから) // R[i] == K+1 → -1 (最後まで満たさない) // それ以外 → R[i] for(int i = 0; i < Q; i++){ if (R[i] == 0) cout << 0 << "\n"; else if (R[i] == K+1) cout << -1 << "\n"; else cout << R[i] << "\n"; } return 0; }