数列分块入门1~9
数列分块入门1~9
数列分块入门 1
分析
板板题,大块打标记,小块打暴力
代码
#include <bits/stdc++.h>
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
分析
区间加法直接整块打标记,查询区间内小于某个值的元素用\(vector\)存储,二分找一下即可
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
vector<int> 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
分析
和上一道题基本雷同
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
vector<int> 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
分析
板板题,直接放代码
代码
#include <bits/stdc++.h>
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
分析
对于一个区间,经过若干次开根后,必定会变成\(1\)或者\(0\),我们把这些区间记录一下,下次操作是把它跳过就行了
代码
#include <bits/stdc++.h>
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
分析
\(vector\)大力乱搞
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int a[maxn], blo, n, nn, shuyu[maxn];
vector<int> 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
分析
两个标记,先乘后加
代码
#include <bits/stdc++.h>
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
分析
大力二分,顺便打个\(lazy\)标记优化一下
代码
#include <bits/stdc++.h>
#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<int> 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
分析
我们维护一个数组\(f[l][r]\)为块\(l\)到块\(r\)之间的最小众数
大区间直接带走,零碎区间暴力枚举+二分查找
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <cmath>
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<int, int> mp;
vector<int> 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 0;
}