LOJ6278. 數列分塊入門 2 題解
阿新 • • 發佈:2021-11-08
涉及操作:
- 區間加法;
- 區間詢問小於某個值 \(x\) 的數的個數。
解題思路:
數列分塊。
每個分塊儲存一個副本並排序(程式中用 vector 容器 vec[i]
來儲存第 i 個分塊中的資訊)。
示例程式:
#include <bits/stdc++.h> using namespace std; const int maxn = 50050; 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) { int ans = 0; for (int i = l; i <= min(bl[l]*blo, r); i ++) if (a[i] + tag[bl[i]] < val) ans ++; if (bl[l] != bl[r]) { for (int i = (bl[r]-1)*blo+1; i <= r; i ++) if (a[i] + tag[bl[i]] < val) ans ++; } for (int i = bl[l]+1; i < bl[r]; i ++) { ans += lower_bound(vec[i].begin(), vec[i].end(), val-tag[i]) - vec[i].begin(); } 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*c) << endl; } } return 0; }