LOJ6279. 數列分塊入門 3 題解
阿新 • • 發佈:2021-11-08
涉及操作:
- 區間加法;
- 區間詢問某個數 \(x\) 的前驅(比其小的最大元素)。
解題思路:
數列分塊。思路和第2題思路幾乎相同,也是每一段副本排序。完整的分塊進行二分查詢。
示例程式:
#include <bits/stdc++.h> using namespace std; const int maxn = 100010; int n, blo, a[maxn], bl[maxn], tag[505]; vector<int> vec[505]; // 重置第p個分塊 void reset(int p) { vec[p].clear(); for (int i = (p-1)*blo+1; i <= min(p*blo, n); i ++) vec[p].push_back(a[i]); sort(vec[p].begin(), vec[p].end()); } // 區間 [l,r] + val void add(int l, int r, int val) { for (int i = l; i <= min(bl[l]*blo, r); i ++) a[i] += val; reset(bl[l]); if (bl[l] != bl[r]) { for (int i = (bl[r]-1)*blo+1; i <= r; i ++) a[i] += val; reset(bl[r]); } for (int i = bl[l]+1; i < bl[r]; i ++) tag[i] += val; } // 返回區間 [l,r] 內小於 val 的數的個數 int query(int l, int r, int val) { bool exist = false; int ans; for (int i = l; i <= min(bl[l]*blo, r); i ++) { if (a[i] + tag[bl[i]] < val) { if (!exist || ans < a[i] + tag[bl[i]]) { exist = true; ans = a[i] + tag[bl[i]]; } } } if (bl[l] != bl[r]) { for (int i = (bl[r]-1)*blo+1; i <= r; i ++) { if (a[i] + tag[bl[i]] < val) { if (!exist || ans < a[i] + tag[bl[i]]) { exist = true; ans = a[i] + tag[bl[i]]; } } } } for (int i = bl[l]+1; i < bl[r]; i ++) { int p = lower_bound(vec[i].begin(), vec[i].end(), val-tag[i]) - vec[i].begin(); if (p) { int x = vec[i][p-1] + tag[i]; if (!exist || ans < x) { exist = true; ans = x; } } } if (!exist) return -1; return ans; } int main() { ios::sync_with_stdio(0); cin >> n; blo = sqrt(n); for (int i = 1; i <= n; i ++) { cin >> a[i]; bl[i] = (i - 1) / blo + 1; } for (int i = 1; i <= bl[n]; i ++) reset(i); for (int i = 0; i < n; i ++) { int op, l, r, c; cin >> op >> l >> r >> c; if (op == 0) { add(l, r, c); } else { cout << query(l, r, c) << endl; } } return 0; }