LOJ #6277. 数列分块入门 1

LOJ #6277. 数列分块入门 1

思路&&代码

区间修改+单点查值

先分块,把这(n)个数分成(sqrt{n})个块,用(add[i])表示这个块修改值的和(增量标记)

区间修改:如果是修改整个块,则直接修改这个块的增量标记,如果不是一整个块,就暴力修改值,如果是多个块,是整块的修改增量标记,不是整块的暴力修改

单点查值:单点查值的结果就是这个位置的值加上这个位置所在块的增量标记的值

时间复杂度(O(nsqrt{n}))

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#define int long long
using namespace std;

const int A = 1e5 + 11;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, t;
int a[A], add[A], L[A], R[A], pos[A];

void change(int l, int r, int c) {
	int p = pos[l], q = pos[r];
	if(p == q) {
		for(int i = l; i <= r; i++) a[i] += c;
		return;
	}
	for(int i = p + 1; i < q; i++) add[i] += c;
	for(int i = l; i <= R[p]; i++) a[i] += c;
	for(int i = L[q]; i <= r; i++) a[i] += c;
}

int ask(int now) {
	int p = pos[now];
	return a[now] + add[p];
}

signed main() {
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	t = sqrt(n);
	for(int i = 1; i <= t; i++) {
		L[i] = (i - 1) * sqrt(n) + 1;
		R[i] = i * sqrt(n);
	}
	if(R[t] < n) t++, L[t] = R[t - 1] + 1, R[t] = n;
	for(int i = 1; i <= t; i++) {
		for(int j = L[i]; j <= R[i]; j++) {
			pos[j] = i;
		}
	}
	m = n;
	while(m--) {
		int opt, l, r, c;
		opt = read(), l = read(), r = read(), c = read();
		if(opt == 0) change(l, r, c);
		else cout << ask(r) << "
";
	}
}
原文地址:https://www.cnblogs.com/loceaner/p/12209062.html