分塊入門練習-2
阿新 • • 發佈:2018-12-10
4.區間加法與求和
給出一個長為 的數列,以及 個操作,操作涉及區間加法,區間求和。
資料範圍:
相對與第一題的單點查詢,需要多維護一個區間的區間和屬性
記錄整塊加的值,維護初始以及非整塊操作時的塊的和
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <vector> #include <set> using namespace std; using LL = long long; LL N; LL block, val[50005], blg[50005], tag[1005], sum[1005]; void add(int, int, int); LL query(int, int, LL); int main(){ ios::sync_with_stdio(false); int i; cin >> N, block = sqrt(N); for(i = 1; i <= N; i++) cin >> val[i]; for(i = 1; i <= N; i++){ blg[i] = (i - 1) / block + 1; sum[blg[i]] += val[i]; } for(i = 1; i <= N; i++){ int op, x, y, key; cin >> op >> x >> y >> key; if(op == 0) add(x, y, key); else cout << query(x, y, 1LL * key) << endl; } return 0; } void add(int l, int r, int key){ int i, top; for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++) val[i] += key, sum[blg[i]] += key; if(blg[l] != blg[r]) for(i = (blg[r] - 1) * block + 1; i <= r; i++) val[i] += key, sum[blg[i]] += key; for(i = blg[l] + 1; i <= blg[r] - 1; i++) tag[i] += key; } LL query(int l, int r, LL c){ LL MOD = c + 1, res = 0; int i, top; for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++) res += val[i] + tag[blg[i]], res %= MOD; if(blg[l] != blg[r]) for(i = (blg[r] - 1) * block + 1; i <= r; i++) res += val[i] + tag[blg[i]], res %= MOD; for(i = blg[l] + 1; i <= blg[r] - 1; i++) res += (sum[i] + block * tag[i]) % MOD, res %= MOD; return res; }
5.區間開方
給出一個長為 的數列 ,以及 個操作,操作涉及區間開方,區間求和。
資料範圍:
乍一看因為區間值的變更沒有相同規模根本無法區間維護
但可以注意到,一個數至多經過5次開方後變為1,或初始值為0,後續操作則沒影響
故說明一個整塊的更新至多5次,對於整塊維護一個和的屬性,以及記錄區間是否還有大於1的數(是否還會更新)
PS:可以粗略看出(與實際測試)取塊大小為的值時間上更優
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> using namespace std; using LL = long long; LL N; LL block, val[50005], blg[50005], sum[10005]; void update(int, int); LL query(int, int); int main(){ ios::sync_with_stdio(false); int i; cin >> N, block = pow(N, 0.333); for(i = 1; i <= N; i++) cin >> val[i]; for(i = 1; i <= N; i++){ blg[i] = (i - 1) / block + 1; sum[blg[i]] += val[i]; } for(i = 1; i <= N; i++){ int op, x, y, key; cin >> op >> x >> y >> key; if(op == 0) update(x, y); else cout << query(x, y) << endl; } return 0; } bool flag[10005]; void solve(int block_id); void update(int l, int r){ int i, top; if(!flag[blg[l]]) for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++) sum[blg[i]] -= val[i], val[i] = sqrt(val[i]), sum[blg[i]] += val[i]; if(blg[l] != blg[r] && !flag[blg[r]]) for(i = (blg[r] - 1) * block + 1; i <= r; i++) sum[blg[i]] -= val[i], val[i] = sqrt(val[i]), sum[blg[i]] += val[i]; for(i = blg[l] + 1; i <= blg[r] - 1; i++) solve(i); } LL query(int l, int r){ LL res = 0; int i, top; for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++) res += val[i]; if(blg[l] != blg[r]) for(i = (blg[r] - 1) * block + 1; i <= r; i++) res += val[i]; for(i = blg[l] + 1; i <= blg[r] - 1; i++) res += sum[i]; return res; } void solve(int x){ if(flag[x]) return; flag[x] = true; int i, top; sum[x] = 0; for(i = (x - 1) * block + 1, top = min(x * block, 1LL * N); i <= top; i++){ val[i] = sqrt(val[i]); sum[blg[i]] += val[i]; if(val[i] > 1) flag[x] = false; } }
6.在數列中不同位置插入數的維護(分塊的重構)
給出一個長為的數列,以及個操作,操作涉及單點插入,單點詢問(詢問當前數列某位置的值),資料隨機生成。
資料範圍:
如果要穩定的維護應該用平衡樹並加上資料結構的擴張
先介紹一種操作,即數列由於刪除,插入等操作,需要重新選一個合適的塊的大小進行重構
對於這題,先對初始劃分的每個塊維護一個,通過可以確定插入位置與詢問的值
當某個大於(即這個塊過大,x取10就行)就進行重構
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <vector> using namespace std; int N, M; int block; vector<int> ve[1005]; int trans[200005]; void insert(int x, int key); pair<int, int> query(int); int main(){ ios::sync_with_stdio(false); int i; cin >> N, block = sqrt(N); for(i = 1; i <= N; i++){ int x; cin >> x; ve[(i - 1) / block + 1].push_back(x); } M = (N - 1) / block + 1; for(i = 1; i <= N; i++){ int op, x, y, key; cin >> op >> x >> y >> key; if(op == 0) insert(x, y); else{ auto tmp = query(y); cout << ve[tmp.first][tmp.second] << endl; } } return 0; } void rebuild(); void insert(int x, int key){ pair<int, int> tmp = query(x); ve[tmp.first].insert(ve[tmp.first].begin() + tmp.second, key); if(ve[tmp.first].size() > 20 * block){ rebuild(); } } pair<int, int> query(int x){ int i = 1; while(x > ve[i].size()) x -= ve[i].size(), i++; return make_pair(i, x - 1); } void rebuild(){ int i, k; for(i = 1, k = 0; i <= M; i++){ for(auto j:ve[i]) trans[++k] = j; ve[i].clear(); } block = sqrt(k); for(i = 1; i <= k; i++) ve[(i - 1) / block + 1].push_back(trans[i]); M = (k - 1) / block + 1; }