1. 程式人生 > >數列分塊入門1~9

數列分塊入門1~9

# 數列分塊入門1~9 ## 數列分塊入門 1 [題目傳送門](https://loj.ac/problem/6277) ### 分析 闆闆題,大塊打標記,小塊打暴力 ### 程式碼 ``` cpp #include using namespace std; const int maxn = 1e6 + 5; int a[maxn], blo, shuyu[maxn], siz[maxn], sum[maxn], ad[maxn]; void xg(int l, int r, int val) { for (int i = l; i <= min(r, shuyu[l] * blo); i++) { a[i] += val; sum[shuyu[i]] += val; } if (shuyu[l] == shuyu[r]) return; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { a[i] += val; sum[shuyu[i]] += val; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { ad[i] += val; } } int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } blo = (int)sqrt(n); for (int i = 1; i <= n; i++) { shuyu[i] = (i - 1) / blo + 1; siz[shuyu[i]]++; sum[shuyu[i]] += a[i]; } for (int i = 1; i <= n; i++) { int aa, bb, cc, dd; scanf("%d%d%d%d", &aa, &bb, &cc, &dd); if (aa == 0) { xg(bb, cc, dd); } else { printf("%d\n", a[cc] + ad[shuyu[cc]]); } } return 0; } ``` ## 數列分塊入門 2 [題目傳送門](https://loj.ac/problem/6278) ### 分析 區間加法直接整塊打標記,查詢區間內小於某個值的元素用$vector$儲存,二分找一下即可 ### 程式碼 ``` cpp #include using namespace std; const int maxn = 1e6 + 5; vector g[maxn]; int a[maxn], blo, shuyu[maxn], laz[maxn], sum[maxn]; void qk(int id) { g[id].clear(); for (int i = (id - 1) * blo + 1; i <= id * blo; i++) { g[id].push_back(a[i]); } sort(g[id].begin(), g[id].end()); } void ad(int l, int r, int val) { for (int i = l; i <= min(r, shuyu[l] * blo); i++) { a[i] += val; sum[shuyu[i]] += val; } qk(shuyu[l]); if (shuyu[l] == shuyu[r]) return; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { a[i] += val; sum[shuyu[i]] += val; } qk(shuyu[r]); for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { laz[i] += val; } } int cx(int l, int r, int val) { int ans = 0; for (int i = l; i <= min(r, shuyu[l] * blo); i++) { if (a[i] + laz[shuyu[i]] < val) ans++; } if (shuyu[l] == shuyu[r]) return ans; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { if (a[i] + laz[shuyu[i]] < val) ans++; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { ans += lower_bound(g[i].begin(), g[i].end(), val - laz[i]) - g[i].begin(); } return ans; } int main() { int n; scanf("%d", &n); blo = (int)sqrt(n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); shuyu[i] = (i - 1) / blo + 1; g[shuyu[i]].push_back(a[i]); sum[shuyu[i]] += a[i]; } for (int i = 1; i <= shuyu[n]; i++) { sort(g[i].begin(), g[i].end()); } for (int i = 1; i <= n; i++) { int aa, bb, cc, dd; scanf("%d%d%d%d", &aa, &bb, &cc, &dd); if (aa == 0) { ad(bb, cc, dd); } else { printf("%d\n", cx(bb, cc, dd * dd)); } } return 0; } ``` ## 數列分塊入門 3 [題目傳送門](https://loj.ac/problem/6279) ### 分析 和上一道題基本雷同 ### 程式碼 ``` cpp #include
using namespace std; const int maxn = 1e6 + 5; vector g[maxn]; int a[maxn], blo, shuyu[maxn], laz[maxn], sum[maxn]; void qk(int id) { g[id].clear(); for (int i = (id - 1) * blo + 1; i <= id * blo; i++) { g[id].push_back(a[i]); } sort(g[id].begin(), g[id].end()); } void ad(int l, int r, int val) { for (int i = l; i <= min(r, shuyu[l] * blo); i++) { a[i] += val; sum[shuyu[i]] += val; } qk(shuyu[l]); if (shuyu[l] == shuyu[r]) return; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { a[i] += val; sum[shuyu[i]] += val; } qk(shuyu[r]); for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { laz[i] += val; } } int cx(int l, int r, int val) { int qz = -1; for (int i = l; i <= min(r, shuyu[l] * blo); i++) { if (a[i] + laz[shuyu[i]] < val && (abs(val - qz) > abs(val - (a[i] + laz[shuyu[i]])) || qz == -1)) qz = a[i] + laz[shuyu[i]]; } if (shuyu[l] == shuyu[r]) return qz; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { if (a[i] + laz[shuyu[i]] < val && (abs(val - qz) > abs(val - (a[i] + laz[shuyu[i]])) || qz == -1)) qz = a[i] + laz[shuyu[i]]; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { int now = lower_bound(g[i].begin(), g[i].end(), val - laz[i]) - g[i].begin(); if (now == 0) continue; else { if (g[i][now - 1] + laz[i] < val && (abs(val - qz) > abs(val - (g[i][now - 1] + laz[i])) || qz == -1)) qz = g[i][now - 1] + laz[i]; } } return qz; } int main() { int n; scanf("%d", &n); blo = (int)sqrt(n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); shuyu[i] = (i - 1) / blo + 1; g[shuyu[i]].push_back(a[i]); sum[shuyu[i]] += a[i]; } for (int i = 1; i <= shuyu[n]; i++) { sort(g[i].begin(), g[i].end()); } for (int i = 1; i <= n; i++) { int aa, bb, cc, dd; scanf("%d%d%d%d", &aa, &bb, &cc, &dd); if (aa == 0) { ad(bb, cc, dd); } else { printf("%d\n", cx(bb, cc, dd)); } } return 0; } ``` ## 數列分塊入門 4 [題目傳送門](https://loj.ac/problem/6280) ### 分析 闆闆題,直接放程式碼 ### 程式碼 ``` cpp #include
using namespace std; #define int long long const int maxn = 1e6 + 5; int a[maxn], blo, n, shuyu[maxn], sum[maxn], laz[maxn], siz[maxn]; void ad(int l, int r, int val) { for (int i = l; i <= min(shuyu[l] * blo, r); i++) { a[i] += val; sum[shuyu[i]] += val; } if (shuyu[l] == shuyu[r]) return; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { a[i] += val; sum[shuyu[i]] += val; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { laz[i] += val; } } long long cx(int l, int r, int mod) { mod++; long long ans = 0; for (int i = l; i <= min(shuyu[l] * blo, r); i++) { ans += (long long)(a[i] + laz[shuyu[i]]) % mod; } if (shuyu[l] == shuyu[r]) return ans % mod; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { ans += (long long)(a[i] + laz[shuyu[i]]) % mod; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { ans += (long long)(sum[i] + laz[i] * siz[i]) % mod; } return ans % mod; } signed main() { scanf("%lld", &n); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } blo = (int)sqrt(n); for (int i = 1; i <= n; i++) { shuyu[i] = (i - 1) / blo + 1; sum[shuyu[i]] += a[i]; siz[shuyu[i]]++; } for (int i = 1; i <= n; i++) { int aa, bb, cc, dd; scanf("%lld%lld%lld%lld", &aa, &bb, &cc, &dd); if (aa == 0) { ad(bb, cc, dd); } else { printf("%lld\n", cx(bb, cc, dd)); } } return 0; } ``` ## 數列分塊入門 5 [題目傳送門](https://loj.ac/problem/6281) ### 分析 對於一個區間,經過若干次開根後,必定會變成$1$或者$0$,我們把這些區間記錄一下,下次操作是把它跳過就行了 ### 程式碼 ``` cpp #include
using namespace std; const int maxn = 2e6 + 5; #define int long long int a[maxn], blo, n, shuyu[maxn], sum[maxn], siz[maxn], tag[maxn]; void kf(int l, int r) { for (int i = l; i <= min(shuyu[l] * blo, r); i++) { if (tag[shuyu[i]] != -1) continue; sum[shuyu[i]] -= (a[i] - sqrt(a[i])); a[i] = sqrt(a[i]); } if (shuyu[l] == shuyu[r]) return; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { if (tag[shuyu[i]] != -1) continue; sum[shuyu[i]] -= (a[i] - sqrt(a[i])); a[i] = sqrt(a[i]); } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { if (tag[i] != -1) continue; bool is0 = 0, is1 = 0; for (int j = (i - 1) * blo + 1; j <= i * blo; j++) { sum[shuyu[j]] -= (a[j] - sqrt(a[j])); a[j] = sqrt(a[j]); if (a[j] != 1) is1 = 1; if (a[j] != 0) is0 = 1; } if (is1 == 0) tag[i] = 1; else if (is0 == 0) tag[i] = 0; } } int cx(int l, int r) { int ans = 0; for (int i = l; i <= min(shuyu[l] * blo, r); i++) { ans += a[i]; } if (shuyu[l] == shuyu[r]) return ans; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { ans += a[i]; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { if (tag[i] == 0) continue; else if (tag[i] == 1) ans += siz[i]; else ans += sum[i]; } return ans; } signed main() { scanf("%lld", &n); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); tag[i] = -1; } blo = (int)sqrt(n); for (int i = 1; i <= n; i++) { shuyu[i] = (i - 1) / blo + 1; sum[shuyu[i]] += a[i]; siz[shuyu[i]]++; } for (int i = 1; i <= n; i++) { int aa, bb, cc, dd; scanf("%lld%lld%lld%lld", &aa, &bb, &cc, &dd); if (aa == 0) { kf(bb, cc); } else { printf("%lld\n", cx(bb, cc)); } } return 0; } ``` ## 數列分塊入門 6 [題目傳送門](https://loj.ac/problem/6282) ### 分析 $vector$大力亂搞 ### 程式碼 ``` cpp #include using namespace std; const int maxn = 1e6 + 5; int a[maxn], blo, n, nn, shuyu[maxn]; vector g[maxn]; void ad(int wz, int val) { for (int i = shuyu[1]; i <= shuyu[n]; i++) { if (wz > g[i].size()) wz -= g[i].size(); else { g[i].insert(g[i].begin() + wz, val); return; } } } int cx(int wz) { for (int i = shuyu[1]; i <= shuyu[n]; i++) { if (wz > g[i].size()) wz -= g[i].size(); else { return g[i][wz - 1]; } } } int main() { scanf("%d", &n); blo = sqrt(n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++) { g[(i - 1) / blo + 1].push_back(a[i]); shuyu[i] = (i - 1) / blo + 1; } for (int i = 1; i <= n; i++) { int aa, bb, cc, dd; scanf("%d%d%d%d", &aa, &bb, &cc, &dd); if (aa == 0) ad(bb - 1, cc); else printf("%d\n", cx(cc)); } return 0; } ``` ## 數列分塊入門 7 [題目傳送門](https://loj.ac/problem/6283) ### 分析 兩個標記,先乘後加 ### 程式碼 ``` cpp #include using namespace std; const int maxn = 1e6 + 5; const int mod = 10007; int shuyu[maxn], a[maxn], lazj[maxn], lazc[maxn], n, blo; void push_down(int id) { for (int i = (id - 1) * blo + 1; i <= min(n, id * blo); i++) { a[i] = a[i] * lazc[id] % mod + lazj[id] % mod; a[i] %= mod; } lazj[id] = 0, lazc[id] = 1; } void jia(int l, int r, int val) { push_down(shuyu[l]); for (int i = l; i <= min(shuyu[l] * blo, r); i++) { a[i] += val; a[i] %= mod; } if (shuyu[l] == shuyu[r]) return; push_down(shuyu[r]); for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { a[i] += val; a[i] %= mod; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { lazj[i] += val; lazj[i] %= mod; } } void cheng(int l, int r, int val) { push_down(shuyu[l]); for (int i = l; i <= min(shuyu[l] * blo, r); i++) { a[i] *= val; a[i] %= mod; } if (shuyu[l] == shuyu[r]) return; push_down(shuyu[r]); for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { a[i] *= val; a[i] %= mod; } for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { lazj[i] *= val; lazc[i] *= val; lazj[i] %= mod; lazc[i] %= mod; } } int main() { scanf("%d", &n); blo = sqrt(n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++) { shuyu[i] = (i - 1) / blo + 1; lazc[shuyu[i]] = 1; } for (int i = 1; i <= n; i++) { int aa, bb, cc, dd; scanf("%d%d%d%d", &aa, &bb, &cc, &dd); if (aa == 0) { jia(bb, cc, dd % mod); } else if (aa == 1) { cheng(bb, cc, dd % mod); } else { printf("%d\n", (a[cc] * lazc[shuyu[cc]] % mod + lazj[shuyu[cc]]) % mod); } } return 0; } ``` ## 數列分塊入門 8 [題目傳送門](https://loj.ac/problem/6284) ### 分析 大力二分,順便打個$lazy$標記優化一下 ### 程式碼 ``` cpp #include #define fastcall __attribute__((optimize("-O3"))) #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops") #pragma GCC optimize("-falign-jumps") #pragma GCC optimize("-falign-loops") #pragma GCC optimize("-falign-labels") #pragma GCC optimize("-fdevirtualize") #pragma GCC optimize("-fcaller-saves") #pragma GCC optimize("-fcrossjumping") #pragma GCC optimize("-fthread-jumps") #pragma GCC optimize("-funroll-loops") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") #pragma GCC optimize("-fschedule-insns2") #pragma GCC optimize("-fstrict-aliasing") #pragma GCC optimize("-falign-functions") #pragma GCC optimize("-fcse-follow-jumps") #pragma GCC optimize("-fsched-interblock") #pragma GCC optimize("-fpartial-inlining") #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-freorder-functions") #pragma GCC optimize("-findirect-inlining") #pragma GCC optimize("-fhoist-adjacent-loads") #pragma GCC optimize("-frerun-cse-after-loop") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") #pragma GCC optimize("-ftree-switch-conversion") #pragma GCC optimize("-foptimize-sibling-calls") #pragma GCC optimize("-fexpensive-optimizations") #pragma GCC optimize("inline-functions-called-once") #pragma GCC optimize("-fdelete-null-pointer-checks") using namespace std; const int maxn = 1e6 + 5; int blo, shuyu[maxn], a[maxn], n, laz[maxn]; vector g[maxn]; void cp(int id) { if (laz[id] != 0x3f3f3f3f) return; g[id].clear(); for (int i = (id - 1) * blo + 1; i <= min(n, id * blo); i++) { g[id].push_back(a[i]); } sort(g[id].begin(), g[id].end()); } int cx(int l, int r, int val) { int ans = 0; for (int i = l; i <= min(r, shuyu[l] * blo); i++) { if (laz[shuyu[i]] != 0x3f3f3f3f) { if (laz[shuyu[i]] == val) ans++; } else { if (a[i] == val) ans++; } } if (laz[shuyu[l]] != 0x3f3f3f3f) { for (int i = (shuyu[l] - 1) * blo + 1; i <= min(n, shuyu[l] * blo); i++) { if (i < l || i > min(r, shuyu[l] * blo)) a[i] = laz[shuyu[l]]; else a[i] = val; } laz[shuyu[l]] = 0x3f3f3f3f; } else { for (int i = l; i <= min(r, shuyu[l] * blo); i++) { if (i >= l && i <= min(r, shuyu[l] * blo)) a[i] = val; } } cp(shuyu[l]); if (shuyu[l] == shuyu[r]) return ans; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { if (laz[shuyu[i]] != 0x3f3f3f3f) { if (laz[shuyu[i]] == val) ans++; } else { if (a[i] == val) ans++; } } if (laz[shuyu[r]] != 0x3f3f3f3f) { for (int i = (shuyu[r] - 1) * blo + 1; i <= min(n, shuyu[r] * blo); i++) { if (i > r) a[i] = laz[shuyu[r]]; else a[i] = val; } laz[shuyu[r]] = 0x3f3f3f3f; } else { for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { a[i] = val; } } cp(shuyu[r]); for (int i = shuyu[l] + 1; i <= shuyu[r] - 1; i++) { if (laz[i] != 0x3f3f3f3f && laz[i] != val) laz[i] = val; else if (laz[i] == val) ans += g[i].size(); else { int aa = upper_bound(g[i].begin(), g[i].end(), val) - g[i].begin(); int bb = lower_bound(g[i].begin(), g[i].end(), val) - g[i].begin(); ans += aa - bb; } laz[i] = val; } return ans; } int main() { scanf("%d", &n); blo = sqrt(n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++) { shuyu[i] = (i - 1) / blo + 1; g[shuyu[i]].push_back(a[i]); } for (int i = 1; i <= shuyu[n]; i++) { sort(g[i].begin(), g[i].end()); laz[i] = 0x3f3f3f3f; } for (int i = 1; i <= n; i++) { int aa, bb, cc; scanf("%d%d%d", &aa, &bb, &cc); printf("%d\n", cx(aa, bb, cc)); } return 0; } ``` ## 數列分塊入門 9 [題目傳送門](https://loj.ac/problem/6285) ### 分析 我們維護一個數組$f[l][r]$為塊$l$到塊$r$之間的最小眾數 大區間直接帶走,零碎區間暴力列舉+二分查詢 ### 程式碼 ``` cpp #include #include #include #include #include #include #include using namespace std; const int maxn = 1e5 + 5; int f[4000][4005]; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } return x * f; } int a[maxn], shuyu[maxn], cntt, val[maxn], blo, n, cnt[maxn]; map mp; vector g[maxn]; void solve(int id) { memset(cnt, 0, sizeof(cnt)); int mmax = 0, ans = 0; for (int i = (id - 1) * blo + 1; i <= n; i++) { cnt[a[i]]++; int p = shuyu[i]; if (cnt[a[i]] > mmax || (cnt[a[i]] == mmax && val[ans] > val[a[i]])) { mmax = cnt[a[i]]; ans = a[i]; } f[id][p] = ans; } } int cxx(int l, int r, int val) { return upper_bound(g[val].begin(), g[val].end(), r) - lower_bound(g[val].begin(), g[val].end(), l); } int cx(int l, int r) { int mmax = 0, ans = 0; for (int i = l; i <= min(r, shuyu[l] * blo); i++) { int now = cxx(l, r, a[i]); if (now > mmax || (now == mmax && val[ans] > val[a[i]])) { mmax = now; ans = a[i]; } } if (shuyu[l] == shuyu[r]) return ans; for (int i = r; i >= (shuyu[r] - 1) * blo + 1; i--) { int now = cxx(l, r, a[i]); if (now > mmax || (now == mmax && val[ans] > val[a[i]])) { mmax = now; ans = a[i]; } } int noww = f[shuyu[l] + 1][shuyu[r] - 1]; int kk = cxx(l, r, noww); if (kk > mmax || (kk == mmax && val[ans] > val[noww])) { mmax = kk; ans = noww; } return ans; } int main() { n = read(); blo = 30; for (int i = 1; i <= n; i++) { shuyu[i] = (i - 1) / blo + 1; a[i] = read(); if (!mp[a[i]]) { mp[a[i]] = ++cntt; val[cntt] = a[i]; } a[i] = mp[a[i]]; g[a[i]].push_back(i); } for (int i = 1; i <= shuyu[n]; i++) { solve(i); } for (int i = 1; i <= n; i++) { int l = read(), r = read(); if (l > r) swap(l, r); printf("%d\n", val[cx(l, r)]); } return