分块事实上是一种优化的暴力,其空间复杂度是O(mn^1/2)
直接开始说分块是什么东西
当然这里讲解的是noip阶段的分块,我并不知道怎么用分块维护单调队列
那么这种我说的分块只能作为线段树的替代,如果你不会线段树和树状数组的话
例如:给你n个数,m个操作 n,m<=10^5
操作1:询问[l,r]的区间和
操作2:修改[l,r]的值为原来的值+v
我在之前的线段树给出了单点修改,区间查询,显然的对于这里,加上循环肯定是GG的
当然打标记nlogn随便过
树状数组随便过
假设我们都不会
从最简单的枚举
O(mn) 我们有一种看似没用的优化-----循环展开
int ans = 0;
for(int i = 1;i <= n;i++){
ans += i;
}
for(int a = ;a <= n;a += 2){
ans += a;
ans + =a+1;
}
这个只能快常数级别,但这种思想我们是需要的
我们再次考察这n个数
我们把这n个数分成a块 每块长度为s 显然a = n/s
考察询问 暴力的话是从1一个个往右走 显然我们是不需要一个个遍历的,中间多了许多没有必要地枚举
我们枚举完走完第一块的时候,如果下一块中没有r我们可以直接记录区间值,然后跳过
如果遇到了r 暴力枚举就好了
好-------这就是分块的基本思想
但你可能有一个问题
这个s 我们要怎么衡量呢
我们考察它的复杂度
显然第一段和最后一段我们都要暴力扫完
中间的就是其中的块数去掉常数就是O(2s+N/s) 然后用初等的知识
可以理解成耐克函数也可以理解成均值不等式
显然可知当且仅当s = n^1/2时时间最小
这是一个O(n^1/2*m)的比较优秀的暴力
那么修改呢,是不是看起来就很简单了
但有一个问题,我们怎么维护块内的和
你自然会想到我们可以在经过的块上vs
我们由线段树打标记的思想可以知道,我们可以模仿一个colour函数
剩下的两个部分暴力就好了
总结一下
我们在暴力的过程中需要维护3个值
1. z 当前值2.ink 每个快总体上被加上多少3.sum
在这个题目上是没有线段树好的,而且可以预见到这个代码量不会比线段树少多少
但是,那我们为什么在noip阶段还要讲这个呢
因为你线段树代码有可能被不过 现写很难,这个简单一些,树状数组好背但并不好理解,更不好写代码
瞎搞了一波基本思想,但是----------------
由上面写出的题解是不对的→.→
我们要特判r,l在一个块的情况嘿嘿嘿
代码如下
#include
#include
#include
const int N = 10010
using namespace std;
int s = (int)sqrt(n); //s 赋初值
int belong[N];
int query(int l,int r);
int main(){
for(int a = 1;a <= n;a++){
belong[a] = (a - 1) / (s + 1) //预处理
}
for(int a = 1;a <= n;a++){
right[belong[a]] == a;
}
for(int a = 1;a <= n;a++){
sum[belong[a]] += z[a];
}
for(int a = n;a >= 1;a--){
left[belong[a]] = a;
}
}
int query(int l,int r){
int ans = 0;
if(belong[l] == belong[r]){
for(int i = 1;i <= r;i++){
ans += z[a] + col[belong[a]]
}
} // 特判的内容判断lr是否在同一块
else {
for(int a = 1;a <= right[belong[l]];a++){
ans += z[a] + col[belong[a]];
}
for(int a = belong[l] + 1;a < belong[r];a++){
ans += sum[a];
}
for(int a = left[belong[r]];a <= r;a++){
ans += z[a] + col[belong[a]]
}
}
return ans;
}
void modify(int l,int r,inr v){
if(belong[l] == belong[r]){
for(int a = l;a <= r;a++){
z[a] += v;
sum[belong[a]] += v;
}
}
else{
for(int a = q;a <= right[belong[l]];a++){
z[a] += v;
sum[belong[a]] += v;
}
for(int i = belong[l] + 1;i < belong[r];a++){
col[a] += v;
}
for(int a = left[belong[r]];a <= r;a++){
z[a] += v;
sum[belong[a]] += v;
}
}
}