优雅的暴力优化

发布时间 2023-10-03 21:03:36作者: Biuld

分块

数列分块入门题
好的博客

分块即为将整个序列分为多个块来处理区间信息,常的操作需支持修改和查询。
一个区间,它一定由一些完整的块和剩余的单点。对于完整的块,我们直接对整个块一起做修改和查询;对于剩余的单点,我们直接暴力修改。

通常块长被分为 \(\sqrt{n}\) ,时间复杂度为 \(O(n\sqrt{n})\)

代码模板:

int n, a[N]; //原数组

int p, pos[N]; //块长 和 每个点属于的块编号
int m, l[N], r[N]; //块的数量 和 每个块的左右端点
int b[N], k[N]; //查询用数组 和 记录块修改的数组

inline void work(){ //预处理
	p = sqrt(n);
	m = ceil(1.0 * n / p); //计算块数
	
	for(int i = 1; i <= m; ++ i){
		l[i] = r[i - 1] + 1;
		r[i] = i * p; //计算块左右端点
		
		for(int j = l[i]; j <= r[i]; ++ j){
			pos[j] = i; //记录当前点块编号
			b[i] = a[i]; //看题目要求
		}
	}
}

inline void add(int x, int y){ //修改区间[x, y]
	for(int i = x; i <= min(y, r[pos[x]]); ++ i){ //左剩余区间
		a[i] + ? //看题目要求
	}
	
	if(pos[x] != pos[y]){ //左右剩余不重
		for(int i = max(l[pos[y]], x); i <= y; ++ i){ //右剩余区间
			a[i] + ? //同上
		}
	}
	
	for(int i = pos[x] + 1; i <= pos[y] - 1; ++ i){ //整块修改
		k[i] + ?//同上
	}
}

inline int ask(int x, int y){ //查询区间
	int sum = 0;
	
	for(int i = x; i <= min(y, r[pos[x]]); ++ i){ //左剩余区间
		sum += a[i]? //看题目要求
	}
	
	if(pos[x] != pos[y]){ //左右剩余不重
		for(int i = max(l[pos[y]], x); i <= y; ++ i){ //右剩余区间
			sum += a[i]? //同上
		}
	}
	
	for(int i = pos[x] + 1; i <= pos[y] - 1; ++ i){ //整块修改
		sum += k[i]? //同上
	}
	
	return sum;
}