題目連接:https://loj.ac/problem/6279c++
給出一個長爲 \(n\) 的數列,以及 \(n\) 個操做,操做涉及區間加法,詢問區間內小於某個值 \(x\) 的前驅(比其小的最大元素)。數組
第一行輸入一個數字 \(n\)。
第二行輸入 \(n\) 個數字,第 \(i\) 個數字爲 \(a_i\),以空格隔開。
接下來輸入 \(n\) 行詢問,每行輸入四個數字 \(opt\)、\(l\)、\(r\)、\(c\),以空格隔開。
若 \(opt=0\),表示將位於\([l,r]\) 之間的數字都加 \(c\)。
若 \(opt=1\),表示詢問 \([l,r]\) 中 \(c\) 的前驅的值(不存在則輸出 \(-1\))。spa
對於每次詢問,輸出一行一個數字表示答案。code
4 1 2 2 3 0 1 3 1 1 1 4 4 0 1 2 2 1 1 2 4
3 -1
對於 \(100%\) 的數據,\(1 \le n \le 100000, -2^{31} \le others,ans \le 2^{31}-1\)。排序
本題和《數列分塊入門 2》思路相似,一樣是開一個數組 \(b\) 並塊內排序,一樣是二分找 \(\le c\) 的最大值。get
實現代碼以下:it
#include <bits/stdc++.h> using namespace std; const int maxn = 100010; int n, m, a[maxn], b[maxn], p[maxn], v[400], op, l, r, c; inline void chk_max(int &a, int b) { if (b == -1) return; if (a == -1 || a < b) a = b; } void update_part(int pid) { int i1 = (pid-1)*m+1, i2 = min(pid*m+1, n+1); // 注意邊界條件 for (int i = i1; i < i2; i ++) b[i] = a[i]; sort(b+i1, b+i2); } void add(int l, int r, int c) { if (p[l] == p[r]) { // 說明在同一個分塊,直接更新 for (int i = l; i <= r; i ++) a[i] += c; update_part(p[l]); return; } if (l % m != 1) { // 說明l不是分塊p[l]的第一個元素 for (int i = l; p[i]==p[l]; i ++) { a[i] += c; } update_part(p[l]); } else v[p[l]] += c; if (r % m != 0) { // 說明r不是分塊p[r]的最後一個元素 for (int i = r; p[i]==p[r]; i --) a[i] += c; update_part(p[r]); } else v[p[r]] += c; for (int i = p[l]+1; i < p[r]; i ++) v[i] += c; } int pre_part(int pid, int c) { int i1 = (pid-1)*m+1, i2 = min(pid*m+1, n+1); int id = lower_bound(b+i1, b+i2, c-v[pid]) - (b+i1); if (id == 0) return -1; return b[i1+id-1]+v[pid]; } int get_pre(int l, int r, int c) { int res = -1; if (p[l] == p[r]) { // 說明在同一個分塊,直接更新 for (int i = l; i <= r; i ++) if (a[i]+v[p[i]] < c) chk_max(res, a[i]+v[p[i]]); return res; } if (l % m != 1) { // 說明l不是分塊p[l]的第一個元素 for (int i = l; p[i]==p[l]; i ++) if (a[i]+v[p[i]] < c) chk_max(res, a[i]+v[p[i]]); } else chk_max(res, pre_part(p[l], c)); if (r % m != 0) { // 說明r不是分塊p[r]的最後一個元素 for (int i = r; p[i]==p[r]; i --) if (a[i]+v[p[i]] < c) chk_max(res, a[i]+v[p[i]]); } else chk_max(res, pre_part(p[r], c)); for (int i = p[l]+1; i < p[r]; i ++) chk_max(res, pre_part(i, c)); return res; } int main() { scanf("%d", &n); m = sqrt(n); for (int i = 1; i <= n; i ++) p[i] = (i-1)/m + 1; for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); for (int i = 1; i <= n; i += m) update_part(p[i]); // 初始化 for (int i = 0; i < n; i ++) { scanf("%d%d%d%d", &op, &l, &r, &c); if (op == 0) add(l, r, c); else printf("%d\n", get_pre(l, r, c)); } return 0; }