學習筆記:分塊
阿新 • • 發佈:2021-12-12
來複習分塊啦,真的好簡單呀。
分塊是優雅的暴力,塊長是分塊的藝術
思路很簡單,大段打標記維護,區域性暴力修改就好啦。
複雜度
由塊長決定,一般塊長取 \(\sqrt n\),時間複雜度為 \(O(n\sqrt n)\),可過 \(10^5\)。
複雜度與塊長關係推導
待補
應用
區間修改單點查詢
傳送門:數列分塊 1
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 50000 + 10; int n; int a[N],spl[N],L[N],R[N],tag[N]; void change(int l,int r,int v) { int p = spl[l],q = spl[r]; if(p == q) { for(int i = l;i <= r;i++) a[i] += v; return ; } if(p == q - 1) { tag[p] += v; tag[q] += v; for(int i = L[p];i < l;i++) a[i] -= v; for(int i = r + 1;i <= R[q];i++) a[i] -= v; return ; } for(int i = p + 1;i <= q - 1;i++) tag[i] += v; for(int i = l;i <= R[p];i++) a[i] += v; for(int i = L[q];i <= r;i++) a[i] += v; } signed main() { scanf("%lld",&n); for(int i = 1;i <= n;i++) scanf("%lld",&a[i]); int block = sqrt(n); for(int i = 1;i <= block;i++) { L[i] = (i - 1) * block + 1; R[i] = i * block; } if(R[block] < n) block++,L[block] = R[block - 1] + 1,R[block] = n; for(int i = 1;i <= block;i++) for(int j = L[i];j <= R[i];j++) spl[j] = i; for(int i = 1;i <= n;i++) { int opt,l,r,v; scanf("%lld%lld%lld%lld",&opt,&l,&r,&v); if(l > r) swap(l,r); if(opt == 0) change(l,r,v); else printf("%lld\n",a[r] + tag[spl[r]]); } return 0; }
區間修改區間求和
傳送門:數列分塊 4
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 50000 + 10; int n,block; int a[N],L[N],R[N],spl[N],sum[N],tag[N]; void change(int l,int r,int v) { int p = spl[l],q = spl[r]; if(p == q) { for(int i = l;i <= r;i++) a[i] += v; sum[p] += v * (r - l + 1); return ; } for(int i = p + 1;i <= q - 1;i++) tag[i] += v; for(int i = l;i <= R[p];i++) a[i] += v; sum[p] += v * (R[p] - l + 1); for(int i = L[q];i <= r;i++) a[i] += v; sum[q] += v * (r - L[q] + 1); } int query(int l,int r,int mod) { int p = spl[l],q = spl[r],res = 0; if(p == q) { for(int i = l;i <= r;i++) res = (res + a[i]) % mod; res = (res + tag[p] * (r - l + 1) % mod) % mod; return res; } for(int i = p + 1;i <= q - 1;i++) res = ((res + sum[i]) % mod + tag[i] * (R[i] - L[i] + 1) % mod) % mod; for(int i = l;i <= R[p];i++) res = (res + a[i]) % mod; res = (res + tag[p] * (R[p] - l + 1) % mod) % mod; for(int i = L[q];i <= r;i++) res = (res + a[i]) % mod; res = (res + tag[q] * (r - L[q] + 1) % mod) % mod; return res; } signed main() { scanf("%lld",&n); for(int i = 1;i <= n;i++) scanf("%lld",&a[i]); block = sqrt(n); for(int i = 1;i <= block;i++) { L[i] = (i - 1) * block + 1; R[i] = i * block; } if(R[block] < n) block++,L[block] = R[block - 1] + 1,R[block] = n; for(int i = 1;i <= block;i++) for(int j = L[i];j <= R[i];j++) spl[j] = i,sum[i] += a[j]; for(int i = 1;i <= n;i++) { int opt,l,r,v; scanf("%lld%lld%lld%lld",&opt,&l,&r,&v); if(opt == 0) change(l,r,v); else printf("%lld\n",query(l,r,v + 1) % (v + 1)); } return 0; }