分块

分块是暴力修改的一种改进
本质是大块整体操作,小块暴力修改,使得时间复杂度控制在\(O(\sqrt{N})\)之内

区查区改

首先把数组分成大约\(\sqrt{N}\)块,每一块确定两个端点
修改操作:

  1. 对于在一段之中的:
    直接修改\(a、sum\)数组
  2. 对于跨段的:
    整段的区间:直接打个增加标记\(add\),不去修改\(a、sum\)数组
    左右的小段部分:依然修改\(a、sum\)数组

查询操作:、

  1. 对于在一段之中的:
    直接累加\(a\)数组
  2. 对于跨段的:
    整段的区间:直接把\(add\)标记乘以长度再加上\(sum\)数组
    左右的小段部分:依然累加\(a\)数组和\(add\)标记乘以两端的长度

由此发现:\(sum\)一直是\(a\)的区间和,真正的\(A\)应该是数组\(a\)加上\(add\)

注意开\(ll\),把\(ll\)的数组放在前面乘

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std ;

typedef long long ll ;
const int N = 100010 ;
const int M = 2010 ;

int n, q, B ;
int pos[N], L[M], R[M] ;
ll a[N], sum[N], add[N] ;

char get() {
	char ch = getchar() ;
	while (!isalpha(ch)) ch = getchar() ;
	return ch ; 
}

void init() {
	B = sqrt(n) ;
	for (int i = 1; i <= B; i++) L[i] = (i - 1) * B + 1, R[i] = i * B ;
	if (R[B] < n) B++, L[B] = R[B - 1] + 1, R[B] = n ;
	for (int i = 1; i <= B; i++)
	for (int j = L[i]; j <= R[i]; j++) {
		pos[j] = i ;
		sum[i] += a[j] ;
	}
}

void modify(int l, int r, ll val) {
	int p = pos[l], q = pos[r] ;
	if (p == q) {
		for (int i = l; i <= r; i++) a[i] += val ;
		sum[p] += val * (r - l + 1) ;
	} else {
		for (int i = p + 1; i <= q - 1; i++) add[i] += val ;
		for (int i = l; i <= R[p]; i++) a[i] += val ;
		sum[p] += val * (R[p] - l + 1) ;
		for (int i = L[q]; i <= r; i++) a[i] += val ;
		sum[q] += val * (r - L[q] + 1) ;
	}
} 

ll query(int l, int r) {
	int p = pos[l], q = pos[r] ;
	ll ans = 0 ;
	if (p == q) {
		for (int i = l; i <= r; i++) ans += a[i] ;
		ans += add[p] * (r - l + 1) ;
	} else {
		for (int i = p + 1; i <= q - 1; i++) ans += sum[i] + add[i] * (R[i] - L[i] + 1) ;
		for (int i = l; i <= R[p]; i++) ans += a[i] ;
		ans += add[p] * (R[p] - l + 1) ;
		for (int i = L[q]; i <= r; i++) ans += a[i] ;
		ans += add[q] * (r - L[q] + 1) ;
	}
	return ans ;
}

int main() {
	scanf("%d%d", &n, &q) ;
	for (int i = 1; i <= n; i++) scanf("%lld", &a[i]) ;
	init() ;
	while (q--) {
		char op = get() ;
		if (op == 'C') {
			int l, r, val ; scanf("%d%d%d", &l, &r, &val) ;
			modify(l, r, val) ;
		} else {
			int l, r ; scanf("%d%d", &l, &r) ;
			printf("%lld\n", query(l, r)) ;
		}
	}
}

posted @ 2023-08-30 23:47  哈奇莱特  阅读(14)  评论(0)    收藏  举报