分块 学习笔记
分块学习笔记
1)设置块的大小
sn=(int)sqrt(n);
if(n/sn>=MX) sn=n/MX;//MX为块的极限大小,若卡空间时用,这时数组与块数量有关的部分可以开小,与块大小有关的部分则要开大,注意。。
2)方便的函数
int loc(int x){//位置x属于哪一块
return x/sn +1;//返回+1是空出第0块来,搞前缀和不用特判什么的
}
int getL(int x){//第x块左端点
return max((x-1)*sn,1);//最左是1,要取max
}
int getR(int x){
return min(x*sn-1,n);//最右是n,要取min
}
3)预处理信息
1)前缀块信息,每块n个信息$n\sqrt n \( 2)块到块信息,每块\)\sqrt n\(个信息\)(\sqrt n)^3=n\sqrt n \( 3)所某块的左端点到右边任意位置的信息,\)n\sqrt n \( 这个最好开\)\sqrt n \sqrt n \(数组,每块留一个0的空位,最后留一个sn的位置记整块总和 **可以\)O(\sqrt n)\(维护\)O(1)$询问解决单点修改区间查询问题*
4)获得答案
BL,BR表示第BL块-第BR块
L,R表示BL块的左端点及BR块的右端点
x, y为询问区间
BL=loc(x),BR=loc(y);
if(BL+1>=BR){//x,y在同一块/相邻两块直接扫过去统计
for(i=x;i<=y;i++) xxx;
}
else{
if(getL(BL)!=x) BL++;
if(getR(BR)!=y) BR--;
L=getL(BL);
R=getR(BR);
ans+=get(BL,BR);
for(i=x;i<L;i++) xxx;
for(i=y;i>r;i++) xxx;
}
5) 注意事项:
预处理数组时注意 初始化