LOJ數列分塊入門 6 題解 重新分塊(重構)
阿新 • • 發佈:2021-11-08
涉及操作:
- 單點插入;
- 單調詢問。
解題思路:
每 \(\sqrt n\) 次插入後,重新把數列平均分一下,重構需要的時間複雜度為 \(O(n)\),重構的次數為 \(O(\sqrt n)\),可以解決這個問題。
但是按照原作者的程式碼,是:如果出現某個分塊的大小大於初始分塊大小的 \(20\) 倍時,再重新分塊。這裡按照這種寫法。
示例程式:
#include <bits/stdc++.h> using namespace std; int n, m, blo, a; vector<int> vec[1010], tmp; void rebuild() { tmp.clear(); for (int i = 1; i <= m; i ++) { for (auto x : vec[i]) tmp.push_back(x); vec[i].clear(); } int sz = tmp.size(); int blo2 = sqrt(sz); for (int i = 0; i < sz; i ++) vec[i/blo2+1].push_back(tmp[i]); m = (sz - 1) / blo2 + 1; } pair<int, int> query(int p) { int x = 1; while (vec[x].size() < p) { p -= vec[x].size(); x ++; } return { x, p-1 }; } void add(int p, int val) { pair<int, int> pi = query(p); int x = pi.first, y = pi.second; vec[x].insert(vec[x].begin() + y, val); if (vec[x].size() > 20*blo) rebuild(); } int main() { ios::sync_with_stdio(0); cin >> n; blo = sqrt(n); for (int i = 1; i <= n; i ++) { cin >> a; vec[(i-1)/blo+1].push_back(a); } m = (n - 1) / blo + 1; for (int i = 0; i < n; i ++) { int op, l, r, c; cin >> op >> l >> r >> c; if (op == 0) add(l, r); else { pair<int, int> pi = query(r); int x = pi.first, y = pi.second; cout << vec[x][y] << endl; } } return 0; }