数列分块入门1
区间修改+单点查询
可以维护一个lazy,分成好多块之后。
区间内覆盖的整个块的直接用每个块的lazy+c, 没有覆盖整个块了就直接暴力修改。
复杂度(operatorname O(n sqrt n))
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 50010
#define M 1010
using namespace std;
int n, tot, ans, block, num;
int l[N], r[N], belong[N];
ll a[N], lazy[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n);
num = n / block; if (n % block) num++;
for (int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = i * block;
r[num] = n;
for (int i = 1; i <= n; i++)
belong[i] = (i - 1) / block + 1;
}
void update(int x, int y, int c) {
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++) a[i] += c;
return;
}
for (int i = x; i <= r[belong[x]]; i++) a[i] += c;
for (int i = l[belong[y]]; i <= y; i++) a[i] += c;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) lazy[i] += c;
}
ll query(int x) {
return a[x] + lazy[belong[x]];
}
int main() {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
build();
for (int i = 1, opt, x, y, c; i <= n; i++) {
opt = read(), x = read(), y = read(), c = read();
if (opt == 0) update(x, y, c);
else printf("%lld
", query(y));
}
return 0;
}
数列分块入门2
区间修改
查询区间l, r内有多少个比c 小的数
区间修改的话就按照上边那种方法修改。
查询我们可以一开始就给每一个块内的答案排序,然后二分查找就行了。
遇到不是完整的块直接暴力修改,然后重新排序。
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 50010
#define M 1010
using namespace std;
int n, m, num, block;
int l[N], r[N], belong[N]; int lazy[N], a[N];
vector<ll> vec[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n);
num = n / block; if (n % block) num++;
r[num] = n;
for (int i = 1; i <= n; i++)
belong[i] = (i - 1) / block + 1, vec[belong[i]].push_back(a[i]);
for (int i = 1; i <= num; i++) {
l[i] = (i - 1) * block + 1, r[i] = i * block;
sort(vec[i].begin(), vec[i].end());
}
}
void resort(int x) {
vec[x].clear();
for (int i = l[x]; i <= r[x]; i++) vec[x].push_back(a[i]);
sort(vec[x].begin(), vec[x].end());
}
void update(int x, int y, int c) {
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++) a[i] += c;
resort(belong[x]);
return;
}
for (int i = x; i <= r[belong[x]]; i++) a[i] += c;
for (int i = l[belong[y]]; i <= y; i++) a[i] += c;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) lazy[i] += c;
resort(belong[x]), resort(belong[y]);
}
int query(int x, int y, int c) {
int ans = 0;
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++)
if (a[i] + lazy[belong[x]] < c) ans++;
return ans;
}
for (int i = x; i <= r[belong[x]]; i++)
if (a[i] + lazy[belong[x]] < c) ans++;
for (int i = l[belong[y]]; i <= y; i++)
if (a[i] + lazy[belong[y]] < c) ans++;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++)
ans += lower_bound(vec[i].begin(), vec[i].end(), c - lazy[i]) - vec[i].begin();
return ans;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1, opt, x, y, c; i <= n; i++) {
opt = read(), x = read(), y = read(), c = read();
if (opt == 0) update(x, y, c);
else printf("%d
", query(x, y, c * c));
}
return 0;
}
数列分块入门3
区间修改+查询区间内某个数的前驱
和上边那种做法类似。
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 1010
using namespace std;
int n, num, block;
int l[N], r[N], lazy[N], belong[N], a[N];
vector<int> vec[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n);
num = n / block; if (n % block) num++;
r[num] = n;
for (int i = 1; i <= n; i++)
belong[i] = (i - 1) / block + 1, vec[belong[i]].push_back(a[i]);
for (int i = 1; i <= num; i++) {
l[i] = (i - 1) * block + 1, r[i] = i * block;
sort(vec[i].begin(), vec[i].end());
}
}
void resort(int x) {
vec[x].clear();
for (int i = l[x]; i <= r[x]; i++) vec[x].push_back(a[i]);
sort(vec[x].begin(), vec[x].end());
}
void update(int x, int y, int c) {
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++) a[i] += c;
resort(belong[x]);
return;
}
for (int i = x; i <= r[belong[x]]; i++) a[i] += c;
for (int i = l[belong[y]]; i <= y; i++) a[i] += c;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) lazy[i] += c;
resort(belong[x]), resort(belong[y]);
}
int query(int x, int y, int c) {
int ans = -1;
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++)
if (a[i] + lazy[belong[x]] < c)
ans = max(ans, a[i] + lazy[belong[i]]);
return ans;
}
for (int i = x; i <= r[belong[x]]; i++)
if (a[i] + lazy[belong[i]] < c) ans = max(ans, a[i] + lazy[belong[i]]);
for (int i = l[belong[y]]; i <= y; i++)
if (a[i] + lazy[belong[i]] < c) ans = max(ans, a[i] + lazy[belong[i]]);
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) {
int pos = lower_bound(vec[i].begin(), vec[i].end(), c - lazy[i]) - vec[i].begin();
if (pos >= 1) ans = max(ans, vec[i][pos - 1] + lazy[i]);
}
return ans;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
build();
for (int i = 1, opt, x, y, c; i <= n; i++) {
opt = read(), x = read(), y = read(), c = read();
if (opt == 0) update(x, y, c);
else printf("%d
", query(x, y, c));
}
return 0;
}
数列分块入门4
区间修改+区间查询
可以开一个sum来存每一个块里的权值和
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 50010
#define M 1010
using namespace std;
int n, num, block;
int l[N], r[N], belong[N]; ll sum[N], lazy[N], a[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n);
num = n / block; if (n % block) num++;
r[num] = n;
for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1;
for (int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = i * block;
for (int i = 1; i <= num; i++)
for (int j = l[i]; j <= r[i]; j++)
sum[i] += a[j];
}
void update(int x, int y, ll c) {
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++) a[i] += c;
sum[belong[x]] += (y - x + 1) * c;
return;
}
for (int i = x; i <= r[belong[x]]; i++) a[i] += c;
for (int i = l[belong[y]]; i <= y; i++) a[i] += c;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) lazy[i] += c;
sum[belong[x]] += (r[belong[x]] - x + 1) * c;
sum[belong[y]] += (y - l[belong[y]] + 1) * c;
}
ll query(int x, int y, ll c) {
ll mod = c + 1, ans = 0;
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++)
ans = (ans + a[i] + lazy[belong[i]]) % mod;
return ans;
}
for (int i = x; i <= r[belong[x]]; i++)
ans = (ans + a[i] + lazy[belong[i]]) % mod;
for (int i = l[belong[y]]; i <= y; i++)
ans = (ans + a[i] + lazy[belong[i]]) % mod;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++)
ans = (ans + sum[i] + block * lazy[i]) % mod;
return ans;
}
signed main() {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
build();
for (int i = 1, opt, x, y, c; i <= n; i++) {
opt = read(), x = read(), y = read(), c = read();
if (opt == 0) update(x, y, c);
else printf("%lld
", query(x, y, c));
}
return 0;
}
数列分块入门5
区间开平方。
众所周知(sqrt{sqrt{sqrt{sqrt{sqrt {2^{32}}}}}} = 1)
所以一个区间开平方开5次就差不多是1或者0
这样的区间不需要再开方。
这个东西很坑
一定要有中间那个int要不然会有精度差,我也不知道为啥。
for (int i = x; i <= y; i++)
tmp += (a[i] - (int)sqrt(a[i])), a[i] = sqrt(a[i]);
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 50010
#define M 1010
using namespace std;
int n, num, block;
int l[N], r[N], belong[N]; ll a[N], sum[N], vis[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n);
num = n / block; if (n % block) num++;
r[num] = n;
for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1;
for (int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = i * block;
for (int i = 1; i <= num; i++)
for (int j = l[i]; j <= r[i]; j++) sum[i] += a[j];
}
void update(int x, int y) {
ll tmp = 0;
if (belong[x] == belong[y]) {
if (vis[belong[x]]) return;
for (int i = x; i <= y; i++)
tmp += (a[i] - (int)sqrt(a[i])), a[i] = sqrt(a[i]);
sum[belong[x]] -= tmp;
return;
}
if (!vis[belong[x]])
for (int i = x; i <= r[belong[x]]; i++)
tmp += a[i] - (int)sqrt(a[i]), a[i] = sqrt(a[i]);
sum[belong[x]] -= tmp;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) {
tmp = 0;
if (vis[i]) continue;
for (int j = l[i]; j <= r[i]; j++)
tmp += a[j] - (int)sqrt(a[j]), a[j] = sqrt(a[j]);
sum[i] -= tmp;
if (tmp == 0) vis[i] = 1;
}
tmp = 0;
if (!vis[belong[y]])
for (int i = l[belong[y]]; i <= y; i++)
tmp += a[i] - (int)sqrt(a[i]), a[i] = sqrt(a[i]);
sum[belong[y]] -= tmp;
}
int query(int x, int y) {
int ans = 0;
if (belong[x] == belong[y]) {
for (int i = x; i <= y; i++) ans += a[i];
return ans;
}
for (int i = x; i <= r[belong[x]]; i++) ans += a[i];
for (int i = l[belong[y]]; i <= y; i++) ans += a[i];
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) ans += sum[i];
return ans;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
build();
for (int i = 1, opt, x, y, c; i <= n; i++) {
opt = read(), x = read(), y = read(), c = read();
if (opt == 0) update(x, y);
else printf("%d
", query(x, y));
}
return 0;
}
数列分块入门6
可以分成好几个块处理
每次插入一个数的时候在某个块中暴力插入
如果当前块大于了块的大小
那么我们重新分配块的大小
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
using namespace std;
int n, m, q, tot, ans, block, num;
int l[N], r[N], belong[N], len[N];
int a[1105][3005], b[1105][3005], sum[N], vis[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n), m = n;
num = n / block; if (n % block) num++;
for (int i = 1; i <= n; i++) {
int kuai = (i - 1) / block + 1;
int x = read();
a[kuai][++len[kuai]] = x;
}
}
void rebuild() {
m += tot, tot = 0;
block = (int)sqrt(m);
int cnt = 0, lenth = 0;
for (int i = 1; i <= num; i++)
for (int j = 1; j <= len[i]; j++) {
cnt++;
int id = (cnt - 1) / block + 1;
b[id][++lenth] = a[i][j];
if (lenth == block) lenth = 0;
}
num = m / block; if (m % block) num++;
for (int i = 1; i <= num; i++) {
if (i != num || m % block == 0) len[i] = block;
else len[i] = m - block * block;
for (int j = 1; j <= len[i]; j++) a[i][j] = b[i][j];
}
}
void update(int x, int y) {
int i, pos = 0;
for (i = 1; i <= block; i++) {
if (pos + len[i] >= x) break;
pos += len[i];
}
len[i]++;
for (int j = len[i]; j >= x - pos + 1; j--) a[i][j] = a[i][j - 1];
a[i][x - pos] = y;
tot++;
if (tot == block) rebuild();
}
ll query(int x) {
int i, pos = 0;
for (i = 1; i <= num; i++) {
if (pos + len[i] >= x) break;
pos += len[i];
}
return a[i][x - pos];
}
int main() {
n = read(), tot = 0;
build();
for (int i = 1, opt, x, y, c; i <= n; i++) {
opt = read(), x = read(), y = read(), c = read();
if (opt == 0) update(x, y);
else printf("%lld
", query(y));
}
return 0;
}
数列分块入门7
判断优先级
显然乘法优先级比假发高,
每次更新的时候如果修改的那个块不是完整的块
先把标记清除,然后在暴力更新。
这个程序厌氧,loj直接wa
忽然发现用Clang 可以过.
//#pragma GCC optimize(2)
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 1010
using namespace std;
const int mod = 10007;
int n, num, block;
int l[N], r[N], lazy[N], tag[N], belong[N], a[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n);
num = n / block; if (n % block) num++;
for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1;
for (int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = i * block, tag[i] = 1;
}
void update_jia(int x, int y, int c) {
if (belong[x] == belong[y]) {
for (int i = l[belong[x]]; i <= r[belong[x]]; i++)
a[i] = ((a[i] * tag[belong[i]]) % mod + lazy[belong[i]]) % mod;
lazy[belong[x]] = 0, tag[belong[x]] = 1;
for (int i = x; i <= y; i++) a[i] = (a[i] + c) % mod;
return;
}
for (int i = l[belong[x]]; i <= r[belong[x]]; i++)
a[i] = ((a[i] * tag[belong[i]]) % mod + lazy[belong[i]]) % mod;
lazy[belong[x]] = 0, tag[belong[x]] = 1;
for (int i = x; i <= r[belong[x]]; i++) a[i] = (a[i] + c) % mod;
for (int i = l[belong[y]]; i <= r[belong[y]]; i++)
a[i] = ((a[i] * tag[belong[i]]) % mod + lazy[belong[i]]) % mod;
lazy[belong[y]] = 0, tag[belong[y]] = 1;
for (int i = l[belong[y]]; i <= y; i++) a[i] = (a[i] + c) % mod;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) lazy[i] = (lazy[i] + c) % mod;
}
void update_cheng(int x, int y, int c) {
if (belong[x] == belong[y]) {
for (int i = l[belong[x]]; i <= r[belong[x]]; i++)
a[i] = ((a[i] * tag[belong[i]]) % mod + lazy[belong[i]]) % mod;
lazy[belong[x]] = 0, tag[belong[x]] = 1;
for (int i = x; i <= y; i++) a[i] = (a[i] * c) % mod;
return;
}
for (int i = l[belong[x]]; i <= r[belong[x]]; i++)
a[i] = ((a[i] * tag[belong[i]]) % mod + lazy[belong[i]]) % mod;
lazy[belong[x]] = 0, tag[belong[x]] = 1;
for (int i = x; i <= r[belong[x]]; i++) a[i] = (a[i] * c) % mod;
for (int i = l[belong[y]]; i <= r[belong[y]]; i++)
a[i] = ((a[i] * tag[belong[i]]) % mod + lazy[belong[i]]) % mod;
lazy[belong[y]] = 0, tag[belong[y]] = 1;
for (int i = l[belong[y]]; i <= y; i++) a[i] = (a[i] * c) % mod;
for (int i = belong[x] + 1; i <= belong[y] - 1; i++)
lazy[i] = (lazy[i] * c) % mod, tag[i] = (tag[i] * c) % mod;
}
int main() {
// freopen("a4.in", "r", stdin);
// freopen("aa.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) cin >> a[i], a[i] %= mod;
build();
for (int i = 1, opt, x, y, c; i <= n; i++) {
cin >> opt, cin >> x, cin >> y, cin >> c;
if (opt == 0) update_jia(x, y, c);
if (opt == 1) update_cheng(x, y, c);
if (opt == 2) printf("%d
", ((a[y] * tag[belong[y]]) % mod + lazy[belong[y]]) % mod);
}
return 0;
}
数列分块入门8
与开平方类似
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 1010
using namespace std;
const int inf = -2147483647;
int n, num, block;
int l[N], r[N], lazy[N], a[N], belong[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void build() {
block = sqrt(n);
num = n / block; if (n % block) num++;
r[num] = n;
for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1;
for (int i = 1; i <= num; i++) l[i] = (i - 1) * block + 1, r[i] = i * block, lazy[i] = inf;
}
int change_query(int x, int y, int c) {
int ans = 0;
if (belong[x] == belong[y]) {
if (lazy[belong[x]] != inf) {
for (int i = l[belong[x]]; i <= r[belong[x]]; i++) a[i] = lazy[belong[i]];
lazy[belong[x]] = inf;
}
for (int i = x; i <= y; i++) {
if (a[i] == c) ans++;
a[i] = c;
}
return ans;
}
if (lazy[belong[x]] != inf) {
for (int i = l[belong[x]]; i <= r[belong[x]]; i++) a[i] = lazy[belong[i]];
lazy[belong[x]] = inf;
}
for (int i = x; i <= r[belong[x]]; i++) {
if (a[i] == c) ans++;
a[i] = c;
}
for (int i = belong[x] + 1; i <= belong[y] - 1; i++) {
if (lazy[i] != inf) {
if (lazy[i] == c) ans += r[belong[i]] - l[belong[i]] + 1;
lazy[i] = c;
continue;
}
for (int j = l[i]; j <= r[i]; j++)
if (a[j] == c) ans++;
lazy[i] = c;
}
if (lazy[belong[y]] != inf) {
for (int i = l[belong[y]]; i <= r[belong[y]]; i++)
a[i] = lazy[belong[i]];
lazy[belong[y]] = inf;
}
for (int i = l[belong[y]]; i <= y; i++) {
if (a[i] == c) ans++;
a[i] = c;
}
return ans;
}
int main() {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
build();
for (int i = 1, x, y, c; i <= n; i++) {
x = read(), y = read(), c = read();
printf("%d
", change_query(x, y, c));
}
return 0;
}