数列分块

数列分块入门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;
}
原文地址:https://www.cnblogs.com/zzz-hhh/p/13597927.html