數列分塊入門1~9
阿新 • • 發佈:2020-08-15
# 數列分塊入門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